是否可以在PHP中将父类强制转换为其子类?如果没有,那么最有效的替代方法是什么?
例如,以下结果导致错误:
<?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 */
答案 0 :(得分:1)
当您声明Bar
扩展Foo
时,默认的Foo
构造函数将调用Bar
构造函数以初始化其父属性(在这种情况下,{{1 }})。如果为子类定义了自定义构造函数,则还应该调用父构造函数。 This section of the PHP documentation describes how this works:
public $test
对于示例中的特定功能,我希望将代码的逻辑放入受保护的构造函数中,并从工厂方法中调用它们:
<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
// In BaseClass constructor
$obj = new BaseClass();
// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();
// In BaseClass constructor
$obj = new OtherSubClass();
请注意,我已将函数<?php
class Foo {
public $test;
protected function __construct() {
$this->test = 123;
}
public static function create(): Foo {
return new self();
}
}
class Bar extends Foo {
public $baz;
protected function __construct() {
parent::__construct();
$this->baz = 456;
}
public static function create(): Foo {
return new self();
}
}
的返回类型更改为始终为create()
。 PHP不允许您更改从父类覆盖的函数的返回类型,并且在两个实例中都使用Foo
即可。
但是,这不是问题。 self
为我们提供了一个Bar::create()
对象,如您所愿。返回类型只必须与Bar
兼容,并且由于Foo
实现了Bar
的接口,因此它被认为是类型兼容的。
您可以使用static
关键字来进一步简化此代码:
Foo
可能不是使用受保护的构造函数,例如因为您已经有一个带有必需参数或类似情况的公共构造函数。在这种情况下,您将不得不求助于其他答案中所解释的内容,创建一个临时<?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)
}
*/
并将属性值复制到新的Foo
对象上:
Bar
答案 1 :(得分:0)
我认为没有内置功能可以做到这一点。您可以在子类中编写一个函数,该函数采用父类的实例并返回具有相同内容的子代。
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;
}
}
答案 2 :(得分:0)
我能够使用以下策略来实现这一点:
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)
} */