开发者

PHP: extend existing class

Is it possible to set the parent of the class? I.e. an instance of the parent class gets i开发者_C百科nstantiated during runtime and then a child class instance extending a certain parent instance gets created. For example:

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

I know that I could just $b = new B(); $b->test = 'changed', but that's not what I'm asking about.


A simple way to accomplish this is like so:

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!"


What you've asked for is not possible in base PHP. There are a few ways to do similar things.

You could use the highly experimental runkit extension. The runkit_class_emancipate and runkit_class_adopt functions should work. However, they operate on entire classes, not instances of a class. This probably limits their usefulness for your application.

If you're trying to emulate the expandable class features of other languages, like Ruby and Perl, runkit_method_add and related functions might be more suitable. Again, however, it still operates on entire classes.

The normally accepted "PHP way" to do things like this is via __call. In fact, with anonymous functions in 5.3, you can do something like...

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!");

You'll note in __call and that in creating the anonymous function that the first argument becomes the instance. That's because PHP 5.3's implementation of anonymous functions can't reference $this. That also means that they can't reference protected or private members of the class. This can be corrected by cloning the instance and using Reflection to expose the protected and private members. See this comment on the anonymous function manual page for an example implementation.

Because of limitations of PHP, you can't directly assign an anonymous function to a property and call it. This example will not work:

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()


No, because $a is a separate instance than $b.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜