在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 */
发布于 2018-08-10 04:17:07
我能够使用以下策略来实现这一点:
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)
} */
发布于 2018-06-27 05:57:19
当您声明Bar
扩展Foo
时,默认的Foo
构造函数调用Bar
构造函数以初始化其父属性(在本例中为public $test
)。如果为子类定义自定义构造函数,则还应调用父构造函数。This section of the PHP documentation describes how this works
<?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()
的返回类型更改为始终为Foo
。PHP不允许您更改从父类覆盖的函数的返回类型,在两个实例中使用self
都可以做到这一点。
然而,这不是问题。正如您所期望的,Bar::create()
为我们提供了一个Bar
对象。返回类型只需要与Foo
兼容,而且因为Bar
实现了Foo
的接口,所以它被认为是类型兼容的。
您可以使用static
关键字进一步简化此代码:
<?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
对象中:
<?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)
}
*/
发布于 2018-06-27 03:51:54
我不认为有任何内置的东西可以做到这一点。您可以在子类中编写一个函数,该函数接受父类的一个实例并返回一个具有相同内容的子类。
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;
}
}
https://stackoverflow.com/questions/51050212
复制相似问题