Dynamically calling functions in PHP

Dynamically calling functions by their name, using input from the user, is a convenient alternative to if statements that allows to conditionally call specific parts of your code.

545 views

Edited: 2021-02-14 05:32

Instead of relying on a series of if statements it is often more useful to call a function or method dynamically, as it tend to make your code much more readable; the way to do that is by using the call_user_func to call a function by name.

One place where this is extremely useful is when creating a router. For those who do not know what a router is, it is basically a piece of code that handles the URLs on a website; a router chooses what code to call depending on the URL requested by a user.

In the following example I first check if a function is callable, and if the case, the function is called; if not, a not found error is shown to the user:

$requested_feature = 'frontpage';

if (is_callable('feature_' . $requested_feature)) {
  call_user_func('feature_' . $requested_feature, $feature_path);
} else {
  http_response_code(404);
  echo 'Page not recognized...';
  exit();
}

This is a form of conditional execution that just uses functions or methods instead of conditional structures like if statements and switch.

You would write the function definitions for each feature as usual:

function feature_frontpage() {
  echo 'You have requested the blog';
  exit();
}

Each function that you allow to call this way should be prefixed with feature_ to prevent users from calling unintended parts of your code.

Dynamically calling methods

The above example was procedural; if you wanted to do this from an object orientated context, you would instead do like so:

$features_object = new features();

if (is_callable([$features_object, 'feature_'.$requested_feature])) {
  call_user_func([$features_object, 'feature_'.$requested_feature], $feature_path);
} else {
  http_response_code(404);
  echo 'Page not recognized...';
  exit();
}

The functions themselves are prefixed with "feature_" to better indicate that they are dynamically called via user-input. In order to call a function, a user could type the function name in a URL parameter that is checked by the application; This might look like so:

$features_object = new features();

$requested_feature = (!empty($_GET['feature_name'])) ? $_GET['feature_name'] : null;

if (is_callable([$features_object, 'feature_'.$requested_feature])) {
  call_user_func([$features_object, 'feature_'.$requested_feature], $feature_path);
} else {
  http_response_code(404);
  echo 'Page not recognized...';
  exit();
}

class features {
  public function feature_blog() {
    echo 'You have requested the blog';
    exit();
  }
  public function feature_frontpage() {
    echo 'You have requested the blog';
    exit();
  }
}

This could then be accessed via an URL in the browsers address bar:

https://example.com/?feature_name=blog

If statements vs call_user_func

As a project grows larger, it increasingly becomes more important that you can extend it dynamically without having to modify the routing code; using call_user_func is considerably more flexible than using if statements to do your routing work.

However, this also comes with limitations. Unfortunately, while class definitions or functions are easier to read, using them to handle routing is still limited in flexibility, and as they grow, they will also get quite cumbersome to work with.

An even better alternative to this approach is to keep your routing code in external files, and then load it dynamically based on the file name; the concept is the same, but you are just using file_exists to check if a file exists before attempting to include it, instead of using is_callable.

Links

  1. is_callable - php.net
  2. call_user_func - php.net

Tell us what you think:

  1. How to use the AVIF image format in PHP; A1 or AVIF is a new image format that offers better compression than WebP, JPEG and PNG, and that already works in Google Chrome.
  2. How to create a router in PHP to handle different request types, paths, and request parameters.
  3. How much faster is C++ than PHP to increment and display a counter in a loop?
  4. Detecting the request method used to fetch a web page with PHP, routing, HTTP responses, and more.
  5. How to create a custom error handler for PHP that handles non-fetal errors.

More in: PHP Tutorials