关于继承:PHP:如何将子类__construct()参数传递给parent :: __ construct()?

PHP: How to Pass child class __construct() arguments to parent::__construct()?

我有一个类似这样的PHP类:

1
2
3
4
5
class ParentClass {
    function __construct($arg) {
        // Initialize a/some variable(s) based on $arg
    }
}

它有一个子类,例如:

1
2
3
4
5
6
class ChildClass extends ParentClass {
    function __construct($arg) {
        // Let the parent handle construction.
        parent::__construct($arg);
    }
}

如果出于某种原因,ParentClass需要更改为接受多个可选参数,我希望我的子类提供"以防万一"参数,该怎么办?除非我重新编写childclass代码,否则它将只把一个参数带到构造函数,并且只传递一个参数。

这是如此罕见还是如此糟糕,以至于通常情况下,子类不需要从采用不同参数的ParentClass继承?

基本上,我在python中看到过,在这里可以通过somefunction(*args)将可能未知数量的参数传递给函数,其中"args"是某种类型的数组/iterable。PHP中是否存在类似的内容?或者我应该在继续之前重构这些类吗?


这可以在php>5.6中通过使用EDOCX1(splat)操作符在不使用call_user_func_array()的情况下完成:

1
2
3
4
public function __construct()
{
    parent::__construct(...func_get_args());
}

在PHP中有类似的内容,尽管有点冗长:

1
2
$args = func_get_args();
call_user_func_array(array($this, 'parent::__construct'), $args);


如果出现PHP嵌套限制错误,请尝试以下操作:

1
2
$args = func_get_args();
call_user_func_array(array('parent', '__construct'), $args);


我的方法(在php 7.1中测试):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ParentClass {
    public function __construct(...$args) {
        print 'Parent: ' . count($args) . PHP_EOL;
    }
}

class ChildClass extends ParentClass {
    public function __construct(...$args) {
        parent::__construct(...$args);
        print 'Child: ' . count($args). PHP_EOL;
    }
}

$child = new ChildClass(1, 2, 3, new stdClass);

//Output:
//Parent: 4
//Child: 4

测试https://3v4l.org/csj68

在这种情况下,父级和子级具有相同的构造函数签名。如果要在父构造函数中解包参数,它也可以工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ParentClass {
    public function __construct($a, $b, $c, $d = null) {
        print 'Parent: ' . $a .  $b .  $c . PHP_EOL;
    }
}

class ChildClass extends ParentClass {
    public function __construct(...$args) {
        parent::__construct(...$args);
    }
}

$child = new ChildClass(1, 2, 3);

//Output: Parent: 123

测试https://3v4l.org/jge1a

值得注意的是,在php>=5.6中,可以强制变量函数的类型(php>=7中的标量类型):

1
2
3
4
5
class ParentClass {
    public function __construct(DateTime ...$args) {
        //Do something
    }
}

在php.net上查看这些函数:

此外,如果要进行可选参数,可以执行以下操作:

1
2
3
4
5
class ParentClass {
    function __construct($arg, $arg2="Default Value") {
        // Initialize a/some variable(s) based on $arg
    }
}

是的,制作一个使用与父类不同的构造函数参数的子类是非常糟糕的做法。尤其是在像PHP这样的语言中,它的支持很差。

当然,在PHP中传递一组"我们可能想要的任何参数"的通用方法是传递一个由配置值数组组成的单个参数。


1
parent::__construct( func_get_args() );