我正在做测试。 鉴于此代码片段
<?php
class Point
{
public $x;
public $y;
public function __construct($x, $y) {
$this->x = $x;
$this->y = $y;
}
}
class Point3D extends Point
{
public $z;
public function __construct($x, $y, $z) {
$this->z = $z;
}
}
$p = new Point3D(1, 2, 3);
echo sprintf('(%d, %d, %d)', $p->x, $p->y, $p->z);
我很困惑,因为正确的答案似乎是:
(0,0,3)
但是$x和$y没有在子类中初始化。 __parent() 没有被调用 当我在沙箱中运行代码时,它确实给出了预期的答案 当我向 ChatGPT 询问此事时,他给出了我会给出的答案:$x, $y 之前未初始化... => 致命错误
问题是为什么我和ChatGPT都错了 这里面的原理是什么?
您的问题与类型化属性有关。当您没有像示例中那样使用类型化属性时,PHP 将尽力使用它所给定的内容。
使用相同的示例,我们可以使用类型提示来强制执行我们的期望,但无需调用父级
<?php
class Point
{
public int $x;
public int $y;
public function __construct(int $x, int $y) {
$this->x = $x;
$this->y = $y;
}
}
class Point3D extends Point
{
public int $z;
public function __construct(int $x, int $y, int $z) {
$this->z = $z;
}
}
$p = new Point3D(1, 2, 3);
echo sprintf('(%d, %d, %d)', $p->x, $p->y, $p->z);
输出:
Fatal error: Uncaught Error: Typed property Point::$x must not be accessed before initialization in /home/user/scripts/code.php:23
Stack trace:
#0 {main}
thrown in /home/user/scripts/code.php on line 23
请注意,上面的致命错误指出了 typed 属性。通过使用强类型代码,PHP 将强制执行这些检查,并在遇到无法确定所提供类型的情况时抛出错误。
另请注意,除非您使用
declare(strict_types=1);
,否则即使在这种情况下传递字符串或其他非整数值,PHP 也会允许这些值通过并自动执行一些类型处理。
也就是说,一旦我们包含父构造函数,一切都将毫无问题地运行:
class Point3D extends Point
{
public int $z;
public function __construct(int $x, int $y, int $z) {
parent::__construct($x, $y);
$this->z = $z;
}
}