PHP: Named Arguments

PHP does not have named parameters build-in, but in this tutorial you can learn how to simulate the functionality with a bit of extra code.

3398 views
d

By. Jacob

Edited: 2021-02-05 19:49

named parameters, PHP tutorial

Named arguments (Also known as named parameters) are available in PHP 8.0, and allows you to pass input data to a function using the name of the argument instead of relying on the order of the function arguments themselves.

Here is a good example of how they may be used in PHP:

$data = file_get_contents(
  filename:'form.html',
  use_include_path: true
);
echo $data;

The individual argument name matches the name of the input variables of the function. If you have a fairly decent code editor, then you just need to hover the a function name to get a small popup with it's definition, including information about argument names; but, the benefit of using argument names will probably be limited due to these same editor-features. One place where named arguments is useful though, is when you want improve readability of your code by omitting unused arguments.

The full function signature for the file_get_contents function is as follows:

function file_get_contents(
    $filename,
    $use_include_path = false,
    $context = null,
    $offset = 0,
    $maxlen = null
) { }

Note. This information is typically available when you hover the function name in your editor. I can recommend Eclipse, or Visual Studio Code with intelephense.

Older versions of PHP do not have names arguments, but it is still possible to simulate the functionality using a combination of arrays and type checks — although I do not personally recommend this — I tried it out for a while, and found it just cluttered my code. Nevertheless, my old solution is still included in the following sections.

If you are working on a larger project, then I warmly recommend you stick with named parameters for custom functions and methods throughout your project. Doing so allows you to more easily change the function or method definition later, without having to change all of the code in your project that depends on the function.

For older versions of PHP

The problem with function arguments in old versions of PHP is that you have to enter them in a specific order for them to work. For user functions, this is problematic when you need to change the arguments a function accepts, since you would then break existing code that uses the function. With named arguments, we do not have these problems.

Now, while PHP does not natively support named parameters, we can get very close by using an associative array instead of using positional parameters.

Ideally, we should choose carefully, and only use arrays for certain functions. It is also not necessary for a function to accept both named- and positional parameters—although it would be pretty neat.

Also, if a function only accepts a couple parameters, and we are fairly sure that the signature is not going to change, it might be best not to complicate it further by using arrays.

Benefits

1. One benefit is that we do not need to remember the order of the function arguments—what matters is the name of the argument.

2. Another benefit is that we no longer have to declare empty values before reaching the argument of interest, unlike in the bad example below:

my_function(false, '', 'this is what we want');

3. Finally, changing the parameter signature of a function will not break existing code using the function. This can be hugely beneficial in larger projects, since you do not have to update your global code just to introduce new function argument.

Disadvantages

Existing implementations of named parameters do not come entirely without disadvantages. While I will discuss some below, there might be more.

1. One of the main disadvantages is that our code editor will not be able to reveal the function arguments by default, and as a result we now need to know about the implementation of the function. I personally think this is a small price to pay, and you could actually fix this with a plugin if you really wanted.

Another possible solution is to reveal the $defined_arguments in an error message when a parameter is either used incorrectly or missing.

2. Finally, having extra code comparing $input_arguments with our $defined_arguments will effect performance a little. Most of the time, this is probably not going to matter much.

Arrays and named parameters

We can either choose to go with an easy solution, like this one:

say_hallo(['name' => 'Jacob', 'email' => '[email protected]']);

function say_hallo($input_arguments=[]) {
    $name = null;
    $email = null;
    extract($input_arguments,EXTR_IF_EXISTS);

    echo 'Name: ' . $name  . PHP_EOL;
    if ($email !== null) {
        echo 'Email: ' . $email . PHP_EOL;
    }
}

Or, we can choose a more secure solution that also shows helpful error messages to the developer.

For example, just by writing little extra code, we can also support type hinting, block unknown parameters, and add support for required and optional parameters. To do so, we only need to define the parameters that is used by our functions.

Calling a function that accepts an array of parameters can be done like this::

// A function with named parameters
say_hallo(['name' => 'Jacob', 'email' => '[email protected]']);

Implementation

In this section I will show how to use arrays as a substitute for named parameters in PHP.

As discussed earlier, when making a new function, we will first have to define the parameters that the function is going to accept. A direct benefit of doing this is that we can now block unknown- and misspelled parameters—something that PHP does not do by itself.

In addition, we can also decide if a parameter should be defined as required or optional, and we may even choose to validate the type of the parameter.

Note. This example uses simple procedural code, you may want to check out the php_helpers class for an object orientated implementation of this code.

In the below example, I am defining parameters in the $defined_arguments variable, which contains the definition of the parameters we wish to allow:

function say_hallo(array $input_arguments) {
  // Define allowed $input_arguments
  $defined_arguments = ['name' => ['required' => true, 'type' => 'string'], 'email' => false];

  // Check that the used parameters is allowed in defined parameters
  handle_arguments($input_arguments, $defined_arguments);
  

  // *****
  // *** Function code
  // ** *
  echo 'Name: ' . $input_arguments['name'] . PHP_EOL;

  // Output the e-mail address only if provided.
  if (isset($input_arguments['email'])) {
    echo 'Email: ' . $input_arguments['email'] . PHP_EOL;
  }
}

The arguments can either be defined as true for required, or false for optional. If you want to also check the type of the parameter, you simply use an array instead of a boolean value. Below is a few more valid examples:

// Required With Type Checking
$defined_arguments = ['name' => ['required' => true, 'type' => 'string'];

// Required Without Type Checking
$defined_arguments = ['name' => true];

// Optional With Type Checking
$defined_arguments = ['name' => ['required' => false, 'type' => 'string'];

// Optional Without Type Checking
$defined_arguments = ['name' => false];

The function will be interrupted with exit(); if a required parameter is not provided.

To handle the argument definitions, we can use a couple of function like this:

function handle_arguments($input_arguments, $defined_arguments) {
  // Check if parameter is defined, and validate the type (if provided)
  foreach ($input_arguments as $key => $value) {
    if (!isset($defined_arguments["$key"])) {
      echo 'Unknown function parameter: ' . $key . PHP_EOL;
      echo 'used in: ' . __FUNCTION__ . PHP_EOL;
      exit();
    }
    // Validate the type, if defined. A type is always defined in an array.
    // I.e.: array('required' => true, 'type' => 'object')
    if (is_array($defined_arguments["$key"])) {
      // Check if the developer remembered to define both "required" and "type"
      if ((!isset($defined_arguments["$key"]['required'])) || (!isset($defined_arguments["$key"]['type']))) {
        echo 'Missing argument definition "required" or "type".';
        exit();
      }
      if (!type_check($value, $defined_arguments["$key"]['type'])) {
        echo 'Invalid input type of: ' . $key . PHP_EOL;
        echo 'used in: ' . __FUNCTION__ . PHP_EOL;
        echo 'Expected ' . $defined_arguments["$key"]['type'] . ', ' . gettype($value) . ' given.' . PHP_EOL;
        exit();
      }
      // In case value was an array, make sure to add possible default elements.
      if ((isset($defined_arguments["$key"]['default'])) && (is_array($defined_arguments["$key"]['default']))) {
        $input_arguments["$key"] += $defined_arguments["$key"]['default'];
      }
    }
  }
  // --------------------------------------------------
  // Check for missing required parameters-------------
  // The "required" setting only needs to be checked when the parameter is missing
  // --------------------------------------------------
  $missing_parms = array_diff_key($defined_arguments, $input_arguments);
  foreach ($missing_parms as $key => $value) {
    if (!is_array($defined_arguments["$key"])) {
      // If no type validation
      if (true === $defined_arguments["$key"]) {
        echo 'Missing required parameter: ' . $key . PHP_EOL;
        echo 'used in: ' . __FUNCTION__ . PHP_EOL;
        exit();
      }
    } else {
      // Check if the developer remembered to define both "required" and "type"
      if ((!isset($defined_arguments["$key"]['required'])) || (!isset($defined_arguments["$key"]['type']))) {
        echo 'Missing argument definition "required" or "type". ';
        exit();
      }
      // If type was to be validated, check the "required" key
      if (true === $defined_arguments["$key"]['required']) {
        echo 'Missing required parameter: ' . $key . PHP_EOL;
        echo 'used in: ' . __FUNCTION__ . PHP_EOL;
        exit();
      }
      // Check if the parameter has a default value
      if (isset($defined_arguments["$key"]['default'])) {
        $input_arguments["$key"] = $defined_arguments["$key"]['default'];
      }
    }
  }
  return $input_arguments;
}
function type_check($input_value, $defined_type) {
    switch ($defined_type) {
        case 'string':
          return is_string($input_value);
        break;
        case 'str':
          return is_string($input_value);
        break;
        case 'integeer':
          return is_int($input_value);
        break;
        case 'int':
          return is_int($input_value);
        break;
        case 'object':
          return is_object($input_value);
        break;
        case 'array':
          return is_array($input_value);
        break;
        case 'bool':
          return is_bool($input_value);
        break;
        case 'resource':
          return is_resource($input_value);
        break;
        case 'null':
          return is_null($input_value);
        break;

        // Mixed type will allow anything
        case 'mixed':
          return true;
        break;

        // For unknown types we return false
        default:
          return false;
        break;
    }
}

Note. The echo statements is simply for demonstration purposes. You can easily replace them with your own error handling.

Now, to call the say_hallo(); function, we can simply do this:

// A function with named parameters
say_hallo(['name' => 'Jacob', 'email' => '[email protected]']);

Links

  1. Named Parameters in PHP - php.net

Tell us what you think:

  1. In this Tutorial, it is shown how to redirect all HTTP requests to a index.php file using htaccess or Apache configuration files.
  2. How to create a router in PHP to handle different request types, paths, and request parameters.
  3. Tutorial on how to use proxy servers with cURL and PHP
  4. When using file_get_contents to perform HTTP requests, the server response headers is stored in a reserved variable after each successful request; we can iterate over this when we need to access individual response headers.
  5. How to effectively use variables within strings to insert bits of data where needed.

More in: PHP Tutorials