2010-07-15 103 views
1

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

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',但是这不是我问。

+0

不,这是不可能的。但是,根据您尝试解决的具体问题,可能有其他解决方法。 – igorw 2010-07-15 10:01:51

回答

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

感谢您的详细解答 – Fluffy 2010-07-15 15:41:32

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

有趣的解决方案,值得尝试。你也不需要'&$ foo'。 '$ foo'就够了。 – instead 2017-11-24 20:12:21

0

没有,因为$a是一个单独的实例比$b