是否可以设置类的父级?即在运行时期间实例化父类的实例,然后创建扩展某个父实例的子类实例。例如:
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 :(得分:1)
基本PHP无法满足您的要求。有几种方法可以做类似的事情。
您可以使用高度实验性的runkit扩展程序。 runkit_class_emancipate和runkit_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
。