Php callable as argument

PHP Programming Best Practices: When to Use Non-Anonymous Callable Arguments

In PHP, a callable is an argument in a function that can be called as a function or a method. Callable arguments can be anonymous functions, closures, methods, or even regular functions.

In some cases, using non-anonymous callable arguments can provide clearer and more maintainable code.

What are Non-Anonymous Callable Arguments?

Non-anonymous callable arguments are named functions or methods that are passed as arguments to another function or method. They can be defined outside of the function that calls them and can be called multiple times from different parts of the codebase.

function addNumbers(int $a, int $b, callable $mathOperation): int < $result = $mathOperation($a, $b); return $result; >function add(int $a, int $b): int < return $a + $b; >$result = addNumbers(5, 10, 'add'); echo $result; // output: 15 

In the above example, we have a function called addNumbers that takes two integers and a callable as arguments. The callable argument represents the mathematical operation to be performed on the integers.

The add function is a named function that takes two integers and adds them. It is then passed as a callable argument to the addNumbers function.

Advantages of Non-Anonymous Callable Arguments

Using named functions or methods as callable arguments has several advantages, including:

Читайте также:  Метод адамса мултона python

1. Code Clarity and Maintainability

Using named functions or methods as callable arguments can make code easier to read and understand, especially if the function or method is used multiple times. It also makes it easier to make changes to the function or method since you only need to modify it in one place, rather than modifying every instance of anonymous functions or closures in your code.

2. Reusability

Named functions or methods can be reused, just like any other function or method, throughout your codebase. This can help reduce code duplication and promote more maintainable code.

3. Testability

Named functions or methods can be unit tested independently of the methods that call them. This makes it easier to write automated tests for your code, which helps catch bugs and errors before they make it into production.

When to Use Non-Anonymous Callable Arguments

While there are advantages to using non-anonymous callable arguments, it’s also important to know when it’s appropriate to use them. Here are some scenarios in which named functions or methods may be a better choice:

1. Code Readability

If the callable argument is only used in one place and is relatively simple, an anonymous function or closure may provide more readable code since it can be defined inline.

2. Context-Specific Functions

If the named function or method is only relevant in the context of the function to which it’s passed, an anonymous function or closure may be a better choice.

3. Code Size/Simplicity

Named functions or methods can add extra overhead to your code and may be unnecessary if the function is relatively simple. In these cases, an anonymous function or closure may suffice.

Conclusion

In summary, using named functions or methods as callable arguments can provide clarity, reusability, and testability benefits to your codebase. However, like any programming decision, there may be situations where anonymous functions or closures are more appropriate. By understanding the pros and cons of each approach, you can make informed decisions about what coding practices to adopt.

Источник

Php callable as argument

Callbacks can be denoted by the callable type declaration.

Some functions like call_user_func() or usort() accept user-defined callback functions as a parameter. Callback functions can not only be simple functions, but also object methods, including static class methods.

Passing

A PHP function is passed by its name as a string . Any built-in or user-defined function can be used, except language constructs such as: array() , echo , empty() , eval() , exit() , isset() , list() , print or unset() .

A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1. Accessing protected and private methods from within a class is allowed.

Static class methods can also be passed without instantiating an object of that class by either, passing the class name instead of an object at index 0, or passing ‘ClassName::methodName’ .

Apart from common user-defined function, anonymous functions and arrow functions can also be passed to a callback parameter.

Note:

As of PHP 8.1.0, anonymous functions can also be created using the first class callable syntax.

Generally, any object implementing __invoke() can also be passed to a callback parameter.

Example #1 Callback function examples

// An example callback function
function my_callback_function () echo ‘hello world!’ ;
>

// An example callback method
class MyClass static function myCallbackMethod () echo ‘Hello World!’ ;
>
>

// Type 1: Simple callback
call_user_func ( ‘my_callback_function’ );

// Type 2: Static class method call
call_user_func (array( ‘MyClass’ , ‘myCallbackMethod’ ));

// Type 3: Object method call
$obj = new MyClass ();
call_user_func (array( $obj , ‘myCallbackMethod’ ));

// Type 4: Static class method call
call_user_func ( ‘MyClass::myCallbackMethod’ );

// Type 5: Relative static class method call
class A public static function who () echo «A\n» ;
>
>

class B extends A public static function who () echo «B\n» ;
>
>

call_user_func (array( ‘B’ , ‘parent::who’ )); // A, deprecated as of PHP 8.2.0

// Type 6: Objects implementing __invoke can be used as callables
class C public function __invoke ( $name ) echo ‘Hello ‘ , $name , «\n» ;
>
>

$c = new C ();
call_user_func ( $c , ‘PHP!’ );
?>

Example #2 Callback example using a Closure

// This is our range of numbers
$numbers = range ( 1 , 5 );

// Use the closure as a callback here to
// double the size of each element in our
// range
$new_numbers = array_map ( $double , $numbers );

print implode ( ‘ ‘ , $new_numbers );
?>

The above example will output:

Note:

Callbacks registered with functions such as call_user_func() and call_user_func_array() will not be called if there is an uncaught exception thrown in a previous callback.

User Contributed Notes 19 notes

You can also use the $this variable to specify a callback:

public $property = ‘Hello World!’ ;

public function MyMethod ()
<
call_user_func (array( $this , ‘myCallbackMethod’ ));
>

public function MyCallbackMethod ()
<
echo $this -> property ;
>

Performance note: The callable type hint, like is_callable(), will trigger an autoload of the class if the value looks like a static method callback.

When specifying a call back in array notation (ie. array($this, «myfunc») ) the method can be private if called from inside the class, but if you call it from outside you’ll get a warning:

class mc <
public function go (array $arr ) <
array_walk ( $arr , array( $this , «walkIt» ));
>

private function walkIt ( $val ) <
echo $val . «
» ;
>

public function export () <
return array( $this , ‘walkIt’ );
>
>

$m = new mc ;
$m -> go ( $data ); // valid

array_walk ( $data , $m -> export ()); // will generate warning

?>

Output:
1
2
3
4

Warning: array_walk() expects parameter 2 to be a valid callback, cannot access private method mc::walkIt() in /in/tfh7f on line 22

A note on differences when calling callbacks as «variable functions» without the use of call_user_func() (e.g. » «):

— Using the name of a function as string has worked since at least 4.3.0
— Calling anonymous functions and invokable objects has worked since 5.3.0
— Using the array structure [$object, ‘method’] has worked since 5.4.0

Note, however, that the following are not supported when calling callbacks as variable functions, even though they are supported by call_user_func():

— Calling static class methods via strings such as ‘foo::doStuff’
— Calling parent method using the [$object, ‘parent::method’] array structure

All of these cases are correctly recognized as callbacks by the ‘callable’ type hint, however. Thus, the following code will produce an error «Fatal error: Call to undefined function foo::doStuff() in /tmp/code.php on line 4»:

class foo static function callIt (callable $callback ) $callback ();
>

static function doStuff () echo «Hello World!» ;
>
>

foo :: callIt ( ‘foo::doStuff’ );
?>

The code would work fine, if we replaced the ‘$callback()’ with ‘call_user_func($callback)’ or if we used the array [‘foo’, ‘doStuff’] as the callback instead.

You can use ‘self::methodName’ as a callable, but this is dangerous. Consider this example:

class Foo public static function doAwesomeThings () FunctionCaller :: callIt ( ‘self::someAwesomeMethod’ );
>

public static function someAwesomeMethod () // fantastic code goes here.
>
>

class FunctionCaller public static function callIt (callable $func ) call_user_func ( $func );
>
>

Foo :: doAwesomeThings ();
?>

This results in an error:
Warning: class ‘FunctionCaller’ does not have a method ‘someAwesomeMethod’.

For this reason you should always use the full class name:
FunctionCaller :: callIt ( ‘Foo::someAwesomeMethod’ );
?>

I believe this is because there is no way for FunctionCaller to know that the string ‘self’ at one point referred to to `Foo`.

> As of PHP 5.2.3, it is also possible to pass ‘ClassName::methodName’

You can also use ‘self::methodName’. This works in PHP 5.2.12 for me.

I needed a function that would determine the type of callable being passed, and, eventually,
normalized it to some extent. Here’s what I came up with:

/**
* The callable types and normalizations are given in the table below:
*
* Callable | Normalization | Type
* ———————————+———————————+—————
* function (. ) use (. ) <. >| function (. ) use (. ) <. >| ‘closure’
* $object | $object | ‘invocable’
* «function» | «function» | ‘function’
* «class::method» | [«class», «method»] | ‘static’
* [«class», «parent::method»] | [«parent of class», «method»] | ‘static’
* [«class», «self::method»] | [«class», «method»] | ‘static’
* [«class», «method»] | [«class», «method»] | ‘static’
* [$object, «parent::method»] | [$object, «parent::method»] | ‘object’
* [$object, «self::method»] | [$object, «method»] | ‘object’
* [$object, «method»] | [$object, «method»] | ‘object’
* ———————————+———————————+—————
* other callable | idem | ‘unknown’
* ———————————+———————————+—————
* not a callable | null | false
*
* If the «strict» parameter is set to true, additional checks are
* performed, in particular:
* — when a callable string of the form «class::method» or a callable array
* of the form [«class», «method»] is given, the method must be a static one,
* — when a callable array of the form [$object, «method»] is given, the
* method must be a non-static one.
*
*/
function callableType ( $callable , $strict = true , callable& $norm = null ) if (! is_callable ( $callable )) switch ( true ) case is_object ( $callable ):
$norm = $callable ;
return ‘Closure’ === get_class ( $callable ) ? ‘closure’ : ‘invocable’ ;
case is_string ( $callable ):
$m = null ;
if ( preg_match ( ‘~^(?[a-z_][a-z0-9_]*)::(?[a-z_][a-z0-9_]*)$~i’ , $callable , $m )) list( $left , $right ) = [ $m [ ‘class’ ], $m [ ‘method’ ]];
if (! $strict || (new \ ReflectionMethod ( $left , $right ))-> isStatic ()) $norm = [ $left , $right ];
return ‘static’ ;
>
> else $norm = $callable ;
return ‘function’ ;
>
break;
case is_array ( $callable ):
$m = null ;
if ( preg_match ( ‘~^(:?(?self|parent)::)?(?[a-z_][a-z0-9_]*)$~i’ , $callable [ 1 ], $m )) if ( is_string ( $callable [ 0 ])) if ( ‘parent’ === strtolower ( $m [ ‘reference’ ])) list( $left , $right ) = [ get_parent_class ( $callable [ 0 ]), $m [ ‘method’ ]];
> else list( $left , $right ) = [ $callable [ 0 ], $m [ ‘method’ ]];
>
if (! $strict || (new \ ReflectionMethod ( $left , $right ))-> isStatic ()) $norm = [ $left , $right ];
return ‘static’ ;
>
> else if ( ‘self’ === strtolower ( $m [ ‘reference’ ])) list( $left , $right ) = [ $callable [ 0 ], $m [ ‘method’ ]];
> else list( $left , $right ) = $callable ;
>
if (! $strict || !(new \ ReflectionMethod ( $left , $right ))-> isStatic ()) $norm = [ $left , $right ];
return ‘object’ ;
>
>
>
break;
>
$norm = $callable ;
return ‘unknown’ ;
>
$norm = null ;
return false ;
>

?>

Hope someone else finds it useful.

Источник

Оцените статью