Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在PHP中如何将父类强制转换为子类?_Php_Oop_Casting_Php 7 - Fatal编程技术网

在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中是否可以将父类强制转换为其子类?如果没有,什么是最有效的替代方案

例如,以下情况会导致错误:

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