PHPで動的なメンバ関数の追加・変更を行う
Tags: ,
Rating:  Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5
Loading ... Loading ...
Palmer @ 2006/06/30 20:00 | コメント(2) トラックバック(0)

PHPはメンバ変数の動的な追加・削除は可能だが、メンバ関数を動的にクラスに追加・変更・削除する機能は無い。PHP5ではオーバーロードが標準でサポートされたが、PHP4にはそういう機能は無いので制限ありだがPHP4/5両対応のクラスを作ってみた。

PHP4での制限:

  • エラー制御演算子(@)をつけないとWarningが発生する
  • 戻り値を受け取ることが出来ない(回避策はあるけど致命的な問題だな・・・)

コード

PHP:
  1. // 動的な関数の追加を可能にするクラス
  2. class DF
  3. {
  4.     function DF() {
  5.         if (version_compare(PHP_VERSION, 5.0, '<'))
  6.             overload(get_class($this));
  7.     }
  8.    
  9.     function _GET_FUNCTION($class, $func) {
  10.         return DF::_(false, $class, $func);
  11.     }
  12.    
  13.     function _SET_FUNCTION($class, $func, $args, $code) {
  14.         DF::_(true, $class, $func, $args, $code);
  15.     }
  16.    
  17.     function _DEL_FUNCTION($class, $func) {
  18.         DF::_(true, $class, $func, "", "");
  19.     }
  20.    
  21.     function _($set, $class, $func, $args = null, $code = null) {
  22.         static $_ = array();
  23.         $class = strtolower($class);
  24.         if ($set) {
  25.             if (class_exists($class))
  26.                 $_[$class][$func] = create_function($args, $code);
  27.         }
  28.         else {
  29.             if (empty($_[$class][$func])) {
  30.                 $class = strtolower(get_parent_class($class));
  31.                 if ($class != 'df')
  32.                     return DF::_GET_FUNCTION($class, $func);
  33.             }
  34.             else
  35.                 return $_[$class][$func];
  36.         }
  37.     }
  38.    
  39.     function __call($func, $args) {
  40.         $f = DF::_GET_FUNCTION(get_class($this), $func);
  41.         if (is_callable($f))
  42.             return call_user_func_array($f, $args);
  43.     }
  44. }
  45.  
  46. // 対象のクラスは上記のクラスを継承する必要がある
  47. class A extends DF {
  48.     function A() { parent::DF(); } // 基底クラスのコンストラクタを必ず呼ぶ
  49. }
  50. $a =& new A();
  51.  
  52. // (A) メンバ関数を追加する前にコールしてみる
  53. echo '(A) '; echo @$a->fn(); echo '<br />';
  54.  
  55. // (B) メンバ関数を動的に追加してコールする
  56. A::_SET_FUNCTION('A', 'fn', '$a', 'echo "{$a} + {$a} = "; return $a + $a;');
  57. echo '(B) '; echo @$a->fn(2); echo '<br />';
  58.  
  59. // (C) 別の関数を同名で上書きする
  60. A::_SET_FUNCTION('A', 'fn', '$a, $b', 'echo "{$a} * {$a} = "; $b = $a * $a;');
  61. echo '(C) '; @$a->fn(3, &$c); echo $c.'<br />';
  62.  
  63. // (D) 派生クラスにも追加したメンバ関数は有効
  64. class B extends A {
  65.     function B() { parent::A(); } // 基底クラスのコンストラクタを必ず呼ぶ
  66. }
  67. $b =& new B();
  68. echo '(D) '; @$b->fn(4, &$d); echo $d.'<br />';
  69.  
  70. // (E) 派生クラスでメンバ関数を無効にする
  71. B::_DEL_FUNCTION('B', 'fn');
  72. echo '(E) '; @$b->fn(5, &$e); echo $e.'<br />';
  73.  
  74. // (F) 派生元ではまだ有効
  75. echo '(F) '; @$a->fn(6, &$f); echo $f.'<br />';


PHP4での実行結果

CODE:
  1. (A)
  2. (B) 2 + 2 =
  3. (C) 3 * 3 = 9
  4. (D) 4 * 4 = 16
  5. (E)
  6. (F) 6 * 6 = 36


PHP5での実行結果

CODE:
  1. (A)
  2. (B) 2 + 2 = 4
  3. (C) 3 * 3 = 9
  4. (D) 4 * 4 = 16
  5. (E)
  6. (F) 6 * 6 = 36


実用性は無くは無い気がするが、著しく可読性の低いコードが出来上がる悪寒・・・。

タグ
トラックバック(0) »
コメント(2)
  • ELf 2006/07/03 11:55

    PHP 4でoverloadは試されましたか?
    http://php.net/overload

  • ELf 2006/07/03 11:56

    とおもったらサンプルに既に書かれていますね
    失礼しました

: 名前
: Email (非公開)
: ウェブサイト