Variadic functions and type-hinting in PHP

╄→尐↘猪︶ㄣ 提交于 2020-01-02 04:15:30

问题


Quick one:

Is there any way to enforce types for variadic functions in PHP? I'm assuming not, however maybe I've missed something.

As of now, I'm just forcing a single required argument of the needed type, and iterating to check the rest.

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

Any better solutions?


Purpose:

A container object that acts as an iterated list of the child objects, with some utility functions. calling it with a variadic constructor would be something like this:

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

The other option could be an addChild method chain:

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

The children take several arguments to their constructor as well, so I'm trying to balance between legibility and processing expense.


回答1:


Well I would say it depends on the number of arguments :) There is nothing like a list (all arguments 1-n as MyClass [before PHP 5.6, for PHP 5.6+ see Variadic functions]), it's more that you need to write each argument (as in your question) and it's allowed to send more but only the ones defined will be checked.

However you can define more and make them optional. Hence why I just wrote it depends on the number of arguments:

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;
    }
}

With such an example, PHP would have thrown the exception already when the argument is not NULL and not MyClass (Passing NULL if given as default value, is possible to pass as well). Optional parameter should not be part of the return value of func_get_args(). I mean, if you don't pass the third argument (here named $object3) it won't appear in the array returned by func_get_args().

No idea if that is more practicable for you than your the code in the question.

If you face more such situations in your code, you can create some sort of helper to validate the input of function calls and delegate to throw the exceptions with nice error message from the helper. That will prevent duplicate code and will give more comfort in development as you can make the exception notices nicer as you write them for multiple cases.


According to your new feedback, if you want first of all the interpreter let the work of checking, a little iteration and the addMember function would do it:

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;
    }
}

Instantiating the object with a wrong type of object in any of the list will prevent the Collection to be instantiated.

you can then just do this:

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



回答2:


This is now possible with PHP 5.6.x, using the ... operator (also known as splat operator in some languages):

Example:

function addDateIntervalsToDateTime( DateTime $dt, DateInterval ...$intervals )
{
    foreach ( $intervals as $interval ) {
        $dt->add( $interval );
    }
    return $dt;
}


来源:https://stackoverflow.com/questions/6300835/variadic-functions-and-type-hinting-in-php

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!