在PHP中如何将父类强制转换为子类?
在PHP中是否可以将父类强制转换为其子类?如果没有,什么是最有效的替代方案 例如,以下情况会导致错误:在PHP中如何将父类强制转换为子类?,php,oop,casting,php-7,Php,Oop,Casting,Php 7,在PHP中是否可以将父类强制转换为其子类?如果没有,什么是最有效的替代方案 例如,以下情况会导致错误: <?php class Foo { public $test; public static function create(): self { $a = new self(); $a->test = 123; return $a; } } class Bar extends Foo { public
<?php
class Foo {
public $test;
public static function create(): self {
$a = new self();
$a->test = 123;
return $a;
}
}
class Bar extends Foo {
public $baz;
public static function create(): self {
$b = (self) parent::create(); // <--- Is this possible?
$b->baz = 456;
return $b;
}
}
$bar = Bar::create();
var_dump($bar); /* should output:
object(Bar)[35]
public 'baz' => int 456
public 'test' => int 123 */
我认为没有任何内置的东西可以做到这一点。您可以在子类中编写一个函数,该函数接受父类的一个实例并返回具有相同内容的子类
class Bar extends Foo {
public static function FooFromBar($foo) {
$bar = new Bar();
$bar->prop1 = $foo->prop1;
$bar->prop2 = $foo->prop2;
// continue for all properties
return $bar;
}
}
当您声明Bar
扩展Foo
时,默认的Foo
构造函数调用Bar
构造函数以初始化其父属性(在本例中,public$test
)。如果为子类定义自定义构造函数,还应调用父构造函数:
这可能是因为使用受保护的构造函数不是一个选项,例如,因为您已经有了一个具有必需参数的公共构造函数或类似情况。在这种情况下,您必须求助于其他答案中的解释,创建一个临时的Foo
,并将属性值复制到一个新的Bar
对象:
<?php
class Foo {
public $test;
public static function create(): Foo {
$result = new self();
$result->test = 123;
return $result;
}
}
class Bar extends Foo {
public $baz;
public static function create(): Foo {
$foo = parent::create();
$result = new self();
foreach($foo as $property => $value) {
$result->$property = $value;
}
$result->baz = 456;
return $result;
}
}
var_dump(Bar::create()); /* Outputs:
object(Bar)#2 (2) {
["baz"]=>
int(456)
["test"]=>
int(123)
}
*/
我能够使用以下策略实现这一点:
class Foo {
public $test;
public static function create(array $row): self {
$a = new static();
$a->test = $row['Test'];
return $a;
}
}
class Bar extends Foo {
public $baz;
public static function create(array $row): Foo {
$b = parent::create($row);
$b->baz = $row['Baz'];
return $b;
}
}
$test = Bar::create([
'Test' => 123,
'Baz' => 456,
]);
var_dump($test);
/* Outputs:
object(Bar)#2 (2) {
["baz"]=> int(456)
["test"]=> int(123)
} */
(self)
应该实现什么?它不是一个有效的强制转换,因为它试图将Foo::create()
的结果强制转换为Bar
的一个实例。数组和stdClass对象强制转换是特殊的。因为它们依赖于引擎盖下的代码,stdClass没有方法,只有属性,所以强制转换很简单。如果要var\u转储,您试图实现什么输出($bar);
?var_dump($bar)
应该输出对象(bar)
。感谢这一极好的信息。看起来好像是将bar
的构造函数公开,然后调用var_dump(new bar());
返回与bar::create()相同的(所需)输出
在您提供的代码中。我是否遗漏了什么?不,这正是预期的行为。有充分的理由使构造函数仅在类内部可用(例如工厂方法模式,即您的create()可能出于不同的原因返回不同的对象类型),但如果您只想在通常使用Foo
对象的情况下使用新的Bar
,那么只需构造Bar
就足够了(请参见:。事实上,这是面向对象编程的关键——编写面向接口(Foo
)的代码,而不是实现(Bar
)。
<?php
class Foo {
public $test;
protected function __construct() {
$this->test = 123;
}
public static function create(): Foo {
return new static();
}
}
class Bar extends Foo {
public $baz;
protected function __construct() {
parent::__construct();
$this->baz = 456;
}
}
var_dump(Bar::create()); /* Outputs:
object(Bar)#1 (2) {
["baz"]=>
int(456)
["test"]=>
int(123)
}
*/
<?php
class Foo {
public $test;
public static function create(): Foo {
$result = new self();
$result->test = 123;
return $result;
}
}
class Bar extends Foo {
public $baz;
public static function create(): Foo {
$foo = parent::create();
$result = new self();
foreach($foo as $property => $value) {
$result->$property = $value;
}
$result->baz = 456;
return $result;
}
}
var_dump(Bar::create()); /* Outputs:
object(Bar)#2 (2) {
["baz"]=>
int(456)
["test"]=>
int(123)
}
*/
class Foo {
public $test;
public static function create(array $row): self {
$a = new static();
$a->test = $row['Test'];
return $a;
}
}
class Bar extends Foo {
public $baz;
public static function create(array $row): Foo {
$b = parent::create($row);
$b->baz = $row['Baz'];
return $b;
}
}
$test = Bar::create([
'Test' => 123,
'Baz' => 456,
]);
var_dump($test);
/* Outputs:
object(Bar)#2 (2) {
["baz"]=> int(456)
["test"]=> int(123)
} */