4

From very long time i am working on php.

But one question may I have no idea about

like I have one function as bellow:

function hello($param1, $param2="2", $param3="3", $param4="4")

Now whenever I will use this function and if I need 4th params thats the $param4 then still I need to call all as blank like this one:

hello(1, '', '', "param4");

So is there any another way to just pass 1st and 4th param in call rather then long list of blanks ?

Or is there any other standard way for this ?

Er.KT
  • 2,852
  • 1
  • 36
  • 70
  • 2
    I don't believe there is a (non-hacky) way to do this with PHP, but would love to be shown I'm wrong. – GrumpyCrouton Feb 09 '18 at 19:56
  • haha, I have dare to ask this question with the same hope, lets when it will be down voted :( – Er.KT Feb 09 '18 at 19:57
  • Also, see this discussion: https://wiki.php.net/rfc/skipparams – lxg Feb 09 '18 at 20:01
  • The difficulty as you see is that passing `''` as a value may override the default set in the function declaration. This may mean having a default of `null` so that passing `null` will be OK. This means though that you have to do some processing at the start of the function to set the real defaults. – Nigel Ren Feb 09 '18 at 20:06
  • in this case, i would use an array of arguments. `$array['param1'];`etc. Then in the function check if the key exists. – Rotimi Feb 09 '18 at 20:11
  • 2
    Alright so simple answer : Its not possible :) – Er.KT Feb 09 '18 at 20:18
  • It will sound humoristic, but just change the order of your parameters, putting $param4 as second parameter. – Pierre François Feb 09 '18 at 20:18
  • If you need to skip parameters, this is a clear sign that your function does too much and you are doing it wrong. Read about Single Responsibility Principle. – Mike Doe Feb 09 '18 at 21:25

4 Answers4

5

There was an RFC for this named skipparams but it was declined.

PHP has no syntactic sugar such as hello(1, , , "param4"); nor hello(1, default, default, "param4"); (per the RFC) for skipping optional parameters when calling a function.

If this is your own function then you can choose the common jQuery style of passing options into plug-ins like this:

function hello( $param1, $more_params = [] )
{
    static $default_params = [
        'param2' => '2',
        'param3' => '3',
        'param4' => '4'
    ];

    $more_params = array_merge( $default_params, $more_params );
}

Now you can:

hello( 1, [ 'param4'=>'not 4, muahaha!' ] );

If your function requires some advanced stuff such as type hinting then instead of array_merge() you will need to manually loop $more_params and enforce the types.

MonkeyZeus
  • 20,375
  • 4
  • 36
  • 77
  • Problem with this is that it has no checks - what if I screw up and use `hello( 1, [ 'parm4'=>'not 4, muahaha!' ] );` – Nigel Ren Feb 09 '18 at 21:03
0

One potential way you can do this, while a little bit hacky, may work well in some situations.

Instead of passing multiple variables, pass a single array variable, and inside the function check if the specific keys exist.

function hello($param1, $variables = ["param2" => "2", "param3" => "3", "param4" => "4"]) {
    if(!array_key_exists("param2", $variables)) $variables['param2'] = "2";
    if(!array_key_exists("param3", $variables)) $variables['param3'] = "3";
    if(!array_key_exists("param4", $variables)) $variables['param4'] = "4";

    echo "<pre>".print_r($variables, true)."</pre>";
}

This will allow you to set "param4" in the above variable, while still remaining default on all of the others.

Calling the function this way:

hello("test", ["param4" => "filling in variable 4"]);

Will result in the output being:

Array
(
    [param4] => filling in variable 4
    [param2] => 2
    [param3] => 3
)

I don't generally recommend this if it can be avoided, but if you absolutely need this functionality, this may work for you.

The key here is that you have a specifically named index inside the array being passed, that you can check against inside the function itself.

GrumpyCrouton
  • 8,486
  • 7
  • 32
  • 71
0

The answer, as I see it, is yes and no.

No, because there's no way to do this in a standard fashion.

Yes, because you can hack around it. This is hacky, but it works ;)

Example:

function some_call($parm1, $parm2='', $parm3='', $parm4='') { ... }

and the sauce:

function some_call_4($parm1, $parm4) {
    return some_call($parm1, '', '', $parm4);
}

So if you make that call ALOT and are tired of typing it out, you can just hack around it.

Sorry, that's all I've got for you.

R. Smith
  • 551
  • 4
  • 10
0

It is an overhead, but you can use ReflectionFunction to create a class, instance of which that can be invoked with named parameters:

final class FunctionWithNamedParams
{
    private $func;

    public function __construct($func)
    {
        $this->func = $func;
    }

    public function __invoke($params = [])
    {
        return ($this->func)(...$this->resolveParams($params));
    }

    private function resolveParams($params)
    {
        $rf = new ReflectionFunction($this->func);

        return array_reduce(
            $rf->getParameters(),
            function ($carry, $param) use ($params) {
                if (isset($params[$param->getName()])) {
                    $carry[] = $params[$param->getName()];
                } else if ($param->isDefaultValueAvailable()) {
                    $carry[] = $param->getDefaultValue();
                } else {
                    throw new BadFunctionCallException;
                }

                return $carry;
            },  
            []
        );
    }
}

Then you can use it like this:

function hello($param1, $param2 = "2", $param3 = "3", $param4 = "4")
{
    var_dump($param1, $param2, $param3, $param4);
}

$func = new FunctionWithNamedParams('hello');

$func(['param1' => '1', 'param4' => 'foo']);

Here is the demo.

sevavietl
  • 3,762
  • 1
  • 14
  • 21