PHP:扩展现有的类

时间:2010-07-15 09:23:03

标签: php oop

是否可以设置类的父级?即在运行时期间实例化父类的实例,然后创建扩展某个父实例的子类实例。例如:

class A {
    var $test = 'default';
}

class B extends A {
    public function __contsruct(A $a) {
        parent = $a; //does not work
    }
}

$a = new A();
$a->test = 'changed';
$b = new B($a);
$b->test == 'changed'; //should be true

我知道我可以$b = new B(); $b->test = 'changed',但那不是我要问的。

3 个答案:

答案 0 :(得分:1)

基本PHP无法满足您的要求。有几种方法可以做类似的事情。

您可以使用高度实验性的runkit扩展程序。 runkit_class_emancipaterunkit_class_adopt函数应该有效。但是,它们对整个类进行操作,而不是对类的实例进行操作。这可能会限制它们对您的应用程序的有用性。

如果您正在尝试模拟其他语言的可扩展类功能,例如Ruby和Perl,runkit_method_add和相关函数可能更合适。但是,它仍然可以在整个类上运行。

通常接受的“PHP方式”来做这样的事情是通过__call。实际上,使用5.3中的anonymous functions,您可以执行类似......

的操作
class Bar {
    public function say($thing) {
        echo "Bar::say says: $thing\n";
    }
}

class Foo extends Bar {
    private $extensions = array();

    public function addExtension($func_name, $func) {
        $this->extensions[ $func_name ] = $func;
    }

    public function __call($func_name, $arguments) {
        array_unshift($arguments, $this);
        if(array_key_exists($func_name, $this->extensions))
            call_user_func_array($this->extensions[ $func_name ], $arguments);
    }
}

$f = new Foo();
$anon = function($obj, $string){ $obj->say($string); };
$f->addExtension('example', $anon);
$f->example("Hello, world!");

你会在__call中注意到,在创建匿名函数时,第一个参数成为实例。那是因为PHP 5.3的匿名函数实现无法引用$this。这也意味着他们无法引用该类的受保护或私有成员。这可以通过克隆实例并使用Reflection来公开受保护和私有成员来纠正。有关示例实现,请参阅this comment on the anonymous function manual page

由于PHP的限制,您无法直接为属性分配匿名函数并调用它。这个例子不起作用:

class WillNotWork {
    public $fatal_error;
}

$broken = new WillNotWork();
$anon = function($arg) { echo "I'm about to create a {$arg} error!"; };
$broken->fatal_error = $anon;
$broken->fatal_error("fatal");
// Fatal error: Call to undefined method WillNotWork::fatal_error()

答案 1 :(得分:1)

实现这一目标的一种简单方法就是这样:

class Foo
{
    function __construct() {
        $this->hello = "Hello";
    }

    public function sayHello() {
        echo $this->hello."!";
    }
}

class Bar
{
    function __construct(&$foo) {
        $this->foo = $foo;
    }

    public function sayHelloAgain() {
        echo $this->foo->sayHello()." Again!";
    }
}

$foo = new Foo();
echo $foo->sayHello(); //outputs "Hello!"

$bar = new Bar($foo);
echo $bar->sayHelloAgain(); //outputs "Hello! Again!"

答案 2 :(得分:0)

不,因为$a是一个单独的实例,而不是$b