如何在PHP中将父类转换为其子类?

时间:2018-06-26 19:33:21

标签: 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 $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 */

3 个答案:

答案 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)
    } */