Ответ 1
В php есть что-то подобное, хотя немного многословное:
$args = func_get_args();
call_user_func_array(array($this, 'parent::__construct'), $args);
У меня есть класс в 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? Или мне нужно реорганизовать эти классы, прежде чем продолжить?
В php есть что-то подобное, хотя немного многословное:
$args = func_get_args();
call_user_func_array(array($this, 'parent::__construct'), $args);
Это можно сделать в PHP >= 5.6 без call_user_func_array()
с помощью оператора ...
(splat):
public function __construct()
{
parent::__construct(...func_get_args());
}
если вы получили ошибку ограничения вложенного файла php, попробуйте следующее:
$args = func_get_args();
call_user_func_array(array('parent', '__construct'), $args);
Мой способ сделать это (проверено в 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
}
}
Проверьте эти функции на php.net:
func_get_args
func_num_args
Кроме того, если вы хотите сделать необязательный аргумент, вы можете сделать это:
class ParentClass {
function __construct($arg, $arg2="Default Value") {
// Initialize a/some variable(s) based on $arg
}
}
Да, довольно плохая практика сделать дочерний класс, который использует разные аргументы конструктора от родителя. Особенно на языке PHP, где он плохо поддерживается.
Конечно, общий способ передать набор "любых аргументов, которые нам могут когда-либо понадобиться" в PHP, - это передать один аргумент, состоящий из массива значений конфигурации.
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());
}
}
parent::__construct( func_get_args() );