FuelPHP動作実験 - oil console & PHP Interactive改を使って マニュアルの例文コピペでいろんなメソッドを試してみよう☆彡

皆様こんにちは! FuelPHP Advent Calendar 2011 17日目です。

昨日は @madmamor さんの 「FuelPHPのcoreクラスを拡張してみる。 」でした。

本日のお題は『oil console & PHP Interactive改を使って マニュアルの例文コピペでいろんなメソッドを試してみよう☆彡』です。

  1. oil console を使ってコマンドラインFuelPHPのメソッドを呼び出してみる。
  2. PHP InteractiveからFuelPHPのメソッドを呼べるように微改造して、マニュアル例文コピペで色んなメソッドを試してみよう。

の開発・学習補助ネタ2本立てでいきます。

(ドキュメントの http://docs.fuelphp.com/packages/oil/console.html が今回該当する箇所になります。)

1. oil consoleって何よ?

FuelPHPのマニュアルを読んでいる最中、ちょっとだけコードの断片を試したい時、何かのコントローラーファイルに

<?php
(上略)
public function action_hogehoge()
{
  $arr1= Arr::average(array('1', 2, 4, '8'));
  var_dump($arr1);

  $arr2 = array('foo', 'bar', 'baz', 'yay');
  Debug::dump(Arr::to_assoc($arr2));

}
(下略)
?>

(Arr Class のお勉強中 - http://docs.fuelphp.com/classes/arr.html

みたいにソースをわざわざ書いてブラウザやIDEで確認するのってカッタルイですよね。
FuelPHPにはそういう時用のconsole機能があり、コマンドラインから色々試すことができます。 ( http://docs.fuelphp.com/packages/oil/console.html)
oilコマンドはソースのREADME.md,fuel,docs,public等と同じ階層にあります。:

    • -

php標準のdate()やdate_sunrise()なんてのを試してみたり、FuelPHPのArr::average()、Arr::to_assoc()を試してる図:

FuelPHPを最初から呼び出せるphp -a みたいなものですね。
ただ、

<?php
  $arr1= Arr::average(array('1', 2, 4, '8'));
  var_dump($arr1);
  $arr2 = array('foo', 'bar', 'baz', 'yay');
  Debug::dump(Arr::to_assoc($arr2));
?>

の様な一行コードをマニュアルからコピペして試したい時にはまあ良いんですが、

<?php
$people = array(
  array(
    "name" => "Jack",
    "age" => 21
  ),
  array(
    "name" => "Jill",
    "age" => 23
  )
);
print_r( Arr::assoc_to_keyval($people, 'name', 'age') );
?>

みたいにコードに改行が入ってしまった場合うまく動きませんorz
うわぁあぁヽ(`Д´)ノキモイヨー :


2. PHP InteractiveでFuelPHPのクラスを呼び出せるようにすればいいんじゃね?

で、このoilコマンドのconsole機能ですが一行毎にreadline()で入力を読み込んでevalしてるわけで複数行対応させるのは面倒。

そこで PHP Interactive - http://www.hping.org/phpinteractive/ の出番です。奥さん。
こいつは改行OKで複数行入力しながら、コードの断片をインタラクティブに動かして試せるスグレモノです。
こんな感じ:

で、PHP InteractiveにFuelPHPのbootstrap.phpを読みこませればいいんじゃね?というわけで微改造してみました。以下その記録。

注意:これはフォーム内に書いたコードをevalして実行してるwebプログラムなので決して公開サーバーに設置しないでください。スパーハカーの餌食、遠隔リモコン君になってしまいます。あくまでも勉強用の外部から繋がらないローカル環境のみで実験してください。

PHP Interactive改でお勉強してるイメージ図:

高級なコーヒーでも飲みながら軽やかにサンプルコードをドラッグ・アンド・ドロップしてupdateボタン押して動作確認。
んで、コードが動いたらその場で少しずつオプションや値を変えたりしながら理解を深めていきます。なんてインテリジェンスなんでしょう!…

では微改造作業に着手しましょう。

以下ローカル環境。外からつながる鯖に決して設置しないこと。スパーハカーの餌食(以下略



作業1:PHP Interactiveのソースをダウンロードする。
ソースは ttp://www.hping.org/phpinteractive/phpinteractive-0.2.tar.gz より取得してください。(サイトは http://www.hping.org/phpinteractive/

作業2:ソースを解凍してpublic/phpinteractive以下に設置、パーミッションもchown,chmodで正しくしておく。

(scripts以下は履歴保存ディレクトリなのでapacheユーザーの書き込み権限必須)


作業3:public/phpinteractive以下に.htaccessを新設
ソース: public/phpinteractive/.htaccess

php_flag short_open_tag On

phpinteractiveのソースがショートオープンタグを使っているのでこのディレクトリ配下のみshort_open_tagを有効にしています。
(サブディレクトリで.htaccessが使えない場合はapacheのconfファイルで AllowOverride Allになっているか要確認)


作業4:public/phpinteractive/includefuel.phpを新設
ソース: public/phpinteractive/includefuel.php

<?php
/**
 * Set error reporting and display errors settings.  You will want to change these when in production.
 */
error_reporting(-1);
ini_set('display_errors', 0);
/**
 * Website document root
 */
define('DOCROOT', dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR);

/**
 * Path to the application directory.
 */
define('APPPATH', realpath(dirname(dirname(__DIR__)).'/fuel/app/').DIRECTORY_SEPARATOR);

/**
 * Path to the default packages directory.
 */
define('PKGPATH', realpath(dirname(dirname(__DIR__)).'/fuel/packages/').DIRECTORY_SEPARATOR);

/**
 * The path to the framework core.
 */
define('COREPATH', realpath(dirname(dirname(__DIR__)).'/fuel/core/').DIRECTORY_SEPARATOR);

// Get the start time and memory for use later
defined('FUEL_START_TIME') or define('FUEL_START_TIME', microtime(true));
defined('FUEL_START_MEM') or define('FUEL_START_MEM', memory_get_usage());

// bypass shutdown_handler
define('MY_INTERACTIVE_MODE', true);

// Boot the app
require APPPATH.'bootstrap.php';

//FUEL_ENV check
if('development'!==\Fuel::$env)
{
  echo 'development mode is required.';
  exit;
}
?>

oilを参考に作りました。MY_INTERACTIVE_MODE の定数は独自に追加しています。
うっかり本番の公開サーバーにアップロードしてしまった時の気休めのため\Fuel::$envがdevelopment以外の時は何もせずここで終了させています。(参考 http://docs.fuelphp.com/installation/instructions.html#/setting_the_environment )


作業5:public/phpinteractive/index.phpを微修正
修正箇所は以下のとおりです。
変更箇所の画面ショット:

オリジナルとの差分:

root@star:/var/vhosts/contact.pizw.net/public/phpinteractive# diff index.php orig_index.php
2d1
< include('./includefuel.php');
94c93
<       if(!@unlink("scripts/$name"))
---
>       if(!@unlink("scripts/$name"))
135c134
<               if (rename_script($current, $newname) == 0)
---
>               if (rename_script($current, $newname) == 0)
441,442c440
<    //echo(htmlentities($code))
<    echo(htmlentities($code, ENT_QUOTES, mb_internal_encoding()));
---
>    echo(htmlentities($code))
498,499c496
<       //$script_output = "<pre>".htmlentities($script_output)."</pre>";
<       $script_output = "<pre>".htmlentities($script_output, ENT_QUOTES, mb_internal_encoding())."</pre>";
---
>       $script_output = "<pre>".htmlentities($script_output)."</pre>";

2行目では新設したincludefuel.phpをincludeしています。これでFuelPHPのクラスが呼べるようになります。
441,498行目付近は日本語文字列を化けないようにする目的での修正です。


作業6:fuel/app/bootstrap.phpでError::のクラスを拡張出来るように変更
ソース: fuel/app/bootstrap.php

<?php

// Load in the Autoloader
require COREPATH.'classes'.DIRECTORY_SEPARATOR.'autoloader.php';
class_alias('Fuel\\Core\\Autoloader', 'Autoloader');

// Bootstrap the framework DO NOT edit this
require COREPATH.'bootstrap.php';


Autoloader::add_classes(array(
	// Add classes you want to override here
	// Example: 'View' => APPPATH.'classes/view.php',
	'Error' => APPPATH.'classes/error.php',//←この行を追加
));

// Register the autoloader
Autoloader::register();

/**
 * Your environment.  Can be set to any of the following:
 *
 * Fuel::DEVELOPMENT
 * Fuel::TEST
 * Fuel::STAGE
 * Fuel::PRODUCTION
 */
Fuel::$env = (isset($_SERVER['FUEL_ENV']) ? $_SERVER['FUEL_ENV'] : Fuel::DEVELOPMENT);

// Initialize the framework with the config file.
Fuel::init('config.php');

?>

PHP Interactiveの入力側でPHPの文法エラーになるような書き方をした場合、fuel/core/classes/error.phpのshutdown_handler()が反応し(fuel/core/bootstrap.php内のregister_shutdown_functionを参照)そこでexitしてしまうのですが、これではPHP Interactiveの画面も表示されなくなり、次の操作に困るため\Error::shutdown_handler()を微変更します。

こんな感じで止まると続行できなくて困るでよ:


作業7:fuel/app/classes/error.phpを新設
コアのクラスファイルを拡張します。(ドキュメント: http://docs.fuelphp.com/general/extending_core.html)
ソース: fuel/app/classes/error.php

<?php
/**
 * Core Class Extends Example (error.php)
 * @package
 * @version 0.01
 * @author mataga
 * @license MIT License
 * @copyright 2011 mataga
 * @link http://twitter.com/mataga
 */
class Error extends Fuel\Core\Error
{

  /**
   * Native PHP shutdown handler
   *
   * @return  string
   */
  public static function shutdown_handler()
  {
    $last_error = error_get_last();

    // Only show valid fatal errors
    if ($last_error AND in_array($last_error['type'], static::$fatal_levels))
    {
      $severity = static::$levels[$last_error['type']];
      logger(Fuel::L_ERROR, $severity.' - '.$last_error['message'].' in '.$last_error['file'].' on line '.$last_error['line']);

      $error = new \ErrorException($last_error['message'], $last_error['type'], 0, $last_error['file'], $last_error['line']);

      //MY_INTERACTIVDE_MODE -- ADD BEGIN
      if(defined('MY_INTERACTIVE_MODE') && MY_INTERACTIVE_MODE)
      {
        echo \Debug::dump($last_error);
        return;
      }
      //MY_INTERACTIVDE_MODE -- ADD END

      if (\Fuel::$env != Fuel::PRODUCTION)
      {
        static::show_php_error($error);
      }
      else
      {
        static::show_production_error($error);
      }

      exit(1);
    }
  }

}//endofclass
/* End of file error.php */
?>

//MY_INTERACTIVDE_MODE で挟んだ5行を追加しただけです。これでパースエラーが起きても PHP Interactive改経由の場合にはこんな感じで処理は続行されます。


作業8:動作確認
ttp://example.com/phpinteractive/ を開いていろいろ試すべし
こんな感じでArr::の実験をしてみたりすると、すぐに細かい動きを確認できて使い方を覚えるわけです。



というわけでFuelPHPのドキュメントサイト( http://docs.fuelphp.com/ )のサンプルコードを動かしまくって、あなたも燃料テイスターになりませんか?

触れば触るほど深い味わいがしますぜ。



明日は @NEKOGET さんの「FuelPHPの呼び方。」になります。

ではでは!