Подтвердить что ты не робот

PHP: Как передать дочерние классы __construct() аргументам parent:: __ construct()?

У меня есть класс в PHP, например:

class ParentClass {
    function __construct($arg) {
        // Initialize a/some variable(s) based on $arg
    }
}

Он имеет дочерний класс, как таковой:

class ChildClass extends ParentClass {
    function __construct($arg) {
        // Let the parent handle construction. 
        parent::__construct($arg); 
    }
}

Что делать, если по какой-то причине ParentClass необходимо изменить, чтобы принять более одного необязательного аргумента, который я бы хотел, чтобы мой класс Child обеспечивал "на всякий случай"? Если я не перекодирую ChildClass, он будет когда-либо принимать только один аргумент конструктору и будет когда-либо передавать только один аргумент.

Является ли такая редкая или такая плохая практика, что обычный случай заключается в том, что ChildClass не нужно наследовать от ParentClass, который принимает разные аргументы?

По существу, я видел в Python, где вы можете передать потенциально неизвестное количество аргументов функции через somefunction(*args), где "args" - это массив/итерируемый какой-либо вид. Что-то вроде этого существует в PHP? Или мне нужно реорганизовать эти классы, прежде чем продолжить?

4b9b3361

Ответ 1

В php есть что-то подобное, хотя немного многословное:

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

Ответ 2

Это можно сделать в PHP >= 5.6 без call_user_func_array() с помощью оператора ... (splat):

public function __construct()
{
    parent::__construct(...func_get_args());
}

Ответ 3

если вы получили ошибку ограничения вложенного файла php, попробуйте следующее:

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

Ответ 4

Мой способ сделать это (проверено в PHP 7.1):

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

В этом случае родительский и дочерний элементы имеют одинаковую подпись конструктора. Это также работает, если вы хотите распаковать ваши аргументы в родительском конструкторе:

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):

class ParentClass {
    public function __construct(DateTime ...$args) {
        //Do something
    }
}

Ответ 5

Проверьте эти функции на php.net:

func_get_args
func_num_args

Кроме того, если вы хотите сделать необязательный аргумент, вы можете сделать это:

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

Ответ 6

Да, довольно плохая практика сделать дочерний класс, который использует разные аргументы конструктора от родителя. Особенно на языке PHP, где он плохо поддерживается.

Конечно, общий способ передать набор "любых аргументов, которые нам могут когда-либо понадобиться" в PHP, - это передать один аргумент, состоящий из массива значений конфигурации.

Ответ 7

PHPStorm Inspection предлагает использовать функцию распаковки аргументов вместо call_user_func_array(). Помимо меньшего количества волшебства, функция быстрее. Источник: https://wiki.php.net/rfc/argument_unpacking

class ChildClass extends ParentClass {
    function __construct($arg) {
        // Let the parent handle construction. 
        parent::__construct(...func_get_args()); 
    }
}

Ответ 8

parent::__construct( func_get_args() );