Вариадические функции и подсказки в PHP - PullRequest
5 голосов
/ 10 июня 2011

Быстрый:

Есть ли способ принудительного применения типов для функций с переменным числом в PHP? Я предполагаю, что нет, но, может быть, я что-то пропустил.

На данный момент я просто заставляю один обязательный аргумент нужного типа и повторяю проверку остальных.

public function myFunction(MyClass $object){
    foreach(func_get_args() as $object){
        if(!($object instanceof MyClass)){
            // throw exception or something
        }
        $this->_objects[] = $object;
    }
}

Есть ли лучшие решения?


Назначение:

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

// returned directly from include
return new MyParent(
    new MyChild($params),
    new MyChild($params),
    new MyChild($params)
);

Другим вариантом может быть addChild цепочка методов:

$parent = new MyParent;
return $parent
    ->addChild(new MyChild($params))
    ->addChild(new MyChild($params))
    ->addChild(new MyChild($params));

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

Ответы [ 2 ]

16 голосов
/ 27 января 2014

Это теперь возможно с PHP 5.6.x , используя оператор ... (также известный как оператор splat в некоторых языках):

Пример:

function addDateIntervalsToDateTime( DateTime $dt, DateInterval ...$intervals )
{
    foreach ( $intervals as $interval ) {
        $dt->add( $interval );
    }
    return $dt;
}
2 голосов
/ 10 июня 2011

Ну, я бы сказал, что это зависит от количества аргументов :) Нет ничего похожего на список (все аргументы 1-n как MyClass [до PHP 5.6, для PHP 5.6+ см. Функции Variadic ]) Более того, вам нужно написать каждый аргумент (как в вашем вопросе), и разрешено отправлять больше, но будут проверяться только те, которые определены.

Однако вы можете определить больше и сделать их необязательными. Следовательно, почему я только что написал, это зависит от количества аргументов:

public function myFunction(MyClass $object, MyClass $object2=null, MyClass $object3=null, MyClass $object4=null, ...){
    foreach(func_get_args() as $object){
        if(null === $object){
            // throw exception or something
        }
        $this->_objects[] = $object;
    }
}

В таком примере PHP выкинул бы исключение уже тогда, когда аргумент не NULL и не MyClass (передавая NULL, если задано в качестве значения по умолчанию, также возможно для передачи). Необязательный параметр не должен быть частью возвращаемого значения func_get_args(). Я имею в виду, что если вы не передадите третий аргумент (здесь он называется $object3), он не появится в массиве, возвращаемом func_get_args().

Не знаю, является ли это более практичным для вас, чем ваш код в вопросе.

Если вы сталкиваетесь с большим количеством таких ситуаций в своем коде, вы можете создать своего рода помощника для проверки ввода вызовов функций и делегировать выдачу исключений с хорошим сообщением об ошибке от помощника. Это предотвратит дублирование кода и даст больше комфорта при разработке, так как вы можете сделать уведомления об исключениях лучше, когда пишете их для нескольких случаев.


Согласно вашему новому отзыву, если вы хотите, прежде всего, чтобы интерпретатор позволил выполнить проверку, небольшая итерация и функция addMember:

class MyParent {
    private $children = array();
    public function __construct() {
        foreach(func_get_args() as $object) $this->addChild($object);
    }
    public function addChild(MyChild $object) {
        $this->children[] = $object;
    }
}

Создание экземпляра объекта с неверным типом объекта в любом из списков предотвратит создание экземпляра коллекции.

тогда вы можете просто сделать это:

// returned directly from include
return new MyParent(
    new MyChild($params),
    new MyChild($params),
    new MyChild($params)
);
...