動的な関数追加を行えるクラス(PHP4/5両対応)
だーいぶ前に別のブログに書いた記事ですが、久しぶりに覗いてみたらまだ残ってたので、役に立つとも思えないけどサルベージしてみた。
<?php class dynamic_func_class { function dynamic_func_class() { if (version_compare(PHP_VERSION, 5.0, '<')) overload(get_class($this)); } function get_dynamic_func($class, $func) { return dynamic_func_class::ref_dynamic_func(false, $class, $func); } function set_dynamic_func($class, $func, $args, $code) { dynamic_func_class::ref_dynamic_func(true, $class, $func, $args, $code); } function remove_dynamic_func($class, $func) { dynamic_func_class::ref_dynamic_func(true, $class, $func, "", ""); } function ref_dynamic_func($set, $class, $func, $args = null, $code = null) { static $_ = array(); $class = strtolower($class); if ($set) { if (class_exists($class)) $_[$class][$func] = create_function($args, $code); } else { if (empty($_[$class][$func])) { $class = strtolower(get_parent_class($class)); if ($class != 'df') return dynamic_func_class::get_dynamic_func($class, $func); } else return $_[$class][$func]; } } function __call($func, $args) { $f = dynamic_func_class::get_dynamic_func(get_class($this), $func); if (is_callable($f)) return call_user_func_array($f, $args); } } // 対象のクラスは上記のクラスを継承する必要がある class A extends dynamic_func_class { function A() { parent::dynamic_func_class(); } // 基底クラスのコンストラクタを必ず呼ぶ } $a =& new A(); // メンバ関数を追加する前にコールしてみる echo @$a->fn(); // php4 => // php5 => // メンバ関数を動的に追加してコールする A::set_dynamic_func('A', 'fn', '$a', 'return $a * $a;'); // function fn($a) { return $a * $a; } echo @$a->fn(2); // echo 2 * 2; // php4 => (PHP4では戻り値を取れない) // php5 => 4 // (C) 別の関数を同名で上書きする A::set_dynamic_func('A', 'fn', '$a, $b', '$b = $a * $a;'); // function fn($a, $b) { $b = $a * $a; } @$a->fn(3, &$c); // $c = 3 * 3; echo $c; // php4 => 9 // php5 => 9 // (D) 派生クラスにも追加したメンバ関数は有効 class B extends A { function B() { parent::A(); } // 基底クラスのコンストラクタを必ず呼ぶ } $b =& new B(); @$b->fn(4, &$d); // $d = 4 * 4; echo $d; // php4 => 16 // php5 => 16 // (E) 派生クラスでメンバ関数を無効にする B::remove_dynamic_func('B', 'fn'); @$b->fn(5, &$e); // $e = 5 * 5; echo $e; // php4 => // php5 => // (F) 派生元ではまだ有効 @$a->fn(6, &$f); echo $f; // php4 => 36 // php5 => 36
うーん、素直にPHP5使うべきだ。