在PHP中,无法进行对象类型转换(除非使用不好的扩展)。一旦实例化了一个对象,就无法再更改类(或其他实现细节)了...
可以通过以下方法模拟它:
public function castAs($newClass) {
$obj = new $newClass;
foreach (get_object_vars($this) as $key => $name) {
$obj->$key = $name;
}
return $obj;
}
使用方法:
$obj = new MyClass();
$obj->foo = 'bar';
$newObj = $obj->castAs('myChildClass');
echo $newObj->foo; // bar
但要注意,它实际上并没有改变原始类。它只是创建了一个新的类。而且要注意,这要求属性是公共的或者具有getter和setter的魔术方法...
如果你想要更多的检查(我建议这样),我会在
castAs
的第一行添加这行代码来防止问题的发生:
if (!$newClass instanceof self) {
throw new InvalidArgumentException(
'Can\'t change class hierarchy, you must cast to a child class'
);
}
好吧,既然Gordon提出了一个非常黑魔法的解决方案,我也会采取同样的方法(使用
RunKit PECL扩展(警告:
这里有危险):)
class myClass {}
class myChildClass extends MyClass {}
function getInstance($classname) {
$tmpclass = 'inheritableClass'.rand(0,9);
while (class_exists($tmpclass))
$tmpclass .= rand(0,9);
$code = 'class '.$tmpclass.' extends '.$classname.' {}';
eval($code);
return new $tmpclass();
}
function castAs($obj, $class) {
$classname = get_class($obj);
if (stripos($classname, 'inheritableClass') !== 0)
throw new InvalidArgumentException(
'Class is not castable'
);
runkit_class_emancipate($classname);
runkit_class_adopt($classname, $class);
}
所以,不要使用
new Foo
,你可以像这样做:
$obj = getInstance('MyClass');
echo $obj instanceof MyChildClass; //false
castAs($obj, 'myChildClass');
echo $obj instanceof MyChildClass; //true
只要使用
getInstance
创建的类内部:
echo $this instanceof MyChildClass; //false
castAs($this, 'myChildClass');
echo $this instanceof MyChildClass; //true
免责声明:不要这样做。真的,不要。虽然可能,但这是一个非常糟糕的主意...