Php callback function this

Practical use of callback functions in PHP

Ability to use function callbacks comes very handy in many everyday programming situations. With anonymous functions it is possible to inject your own code into another function’s execution, which greatly improves code reuse. These are some simple, but highly practical examples of using callbacks for various programming tasks. In each example, we are going to define a helper function that accepts another callback function as an argument and does some processing with it. The helper function can then be reused by calling it repeatedly with custom callback arguments.

Example1: Time measurement

You have probably already used microtime() function for benchmarking your program. Now you can define runWithTimer() helper function, which performs microtime() calls and time subtractions automatically for you. Code intended for time measurement is passed in a callback parameter $cb and called from inside of the helper function.

Helper function

function runWithTimer(callable $cb, &$seconds)  $t0 = microtime(true); try  $res = $cb(); return $res; > finally  $t1 = microtime(true); $seconds = $t1 - $t0; > > 

The helper function uses &$seconds parameter passed by reference to store the resulting number of seconds. Helper function itself returns the return value of the callback function $cb . It could also be implemented the other way round (helper function returning number of seconds and storing callback function return value in an parameter passed by reference).

Usage

$seconds = 0; $res = runWithTimer(function ()  sleep(3); return true; >, $seconds); var_dump($seconds, $res); // Outputs: float(3.022805929184) bool(true) 

Number of seconds the callback function was executing was stored into $seconds variable. Callback function itself returned TRUE , which was stored into the $res variable. Note that doing the final time subtraction in finally block ensures that we get the resulting number of seconds even if the callback function throws an exception.

$seconds = 0; try  $res = runWithTimer(function ()  sleep(3); throw new Exception(); >, $seconds); > catch (Throwable $ex)  >; var_dump($seconds, $res); // Outputs: float(3.0143301486969) NULL 

Example 2: Output buffering

Some of your existing functions may be echoing output instead of returning it as a string. Ideally, you should rewrite those functions to return strings, but as a fast workaround, you can use output buffering. runWithOutputBuffer() helper function encapsulates necessary output buffering calls for you.

Helper function

function runWithOutputBuffer($callback, &$output)  ob_start(); try  $res = $callback(); return $res; > finally  $output = ob_get_contents(); ob_end_clean(); > > 

Usage

$output = ""; $res = runWithOutputBuffer(function ()  echo "Hello world!"; return true; >, $output); var_dump($output, $res); // Outputs: string(12) "Hello world!" bool(true) 

Here, output of callback function was stored as string into $output variable. Callback function itself returned TRUE , which was stored into the $res variable. You could also use string-based callback to easily store output of existing echoing function.

$output = ""; runWithOutputBuffer("phpinfo", $output); var_dump($output); 

Example 3: Database transactions

runInTransaction() function stores repetitive code for committing and rolling back database transactions.

Helper function

function runInTransaction(mysqli $mysqli, callable $cb)  $mysqli->begin_transaction(); try  $res = $cb(); $mysqli->commit(); return $res; > catch (Throwable $ex)  $mysqli->rollback(); throw $ex; > > 

The helper function executes callback $cb and invokes transaction rollback if the callback throws an exception. Otherwise, it commits the transaction. (Callback $cb should contain database data manipulation logic, otherwise it does not make sense to pass it to the runInTransaction() function.) NOTE: In a real project code you would probably implement the helper function as a method of your database connection provider class, so that the $mysqli object could be stored in a class variable instead of being repeatedly passed through function parameter.

Usage

try  $persons = [ ["id" => 1, "name" => "John"], ["id" => 2, "name" => "Monica"], ]; $countInserted = runInTransaction($mysqli, function () use ($persons)  $count = 0; $res = insertIntoTable("persons1", $persons); if ($res === false) throw new Exception; else $count += $res; $res = insertIntoTable("persons2", $persons); if ($res === false) throw new Exception; else $count += $res; return $count; >); echo "Transaction commited ($countInserted rows inserted)."; > catch (Throwable $ex)  echo "Transaction rolled back."; > 

In this example, callback represented by anonymous function inserts data into two different database tables. Database manipulation logic is black-boxed in the insertIntoTable() function. When a database error is signaled by a FALSE return value, callback function throws an exception, and thus causes transaction rollback. Otherwise, it returns number of inserted rows, which is finally stored in $coutInserted variable. Since $persons data intended for database insertion were defined outside the scope of the anonymous function, we have applied use construct in anonymous function definition to bring $perons variable into the inner scope ( function () use ($persons) ). NOTE: You could use similar helper functions even for other database-related tasks, like executing callback functions against certain default database (you would probably use $mysqli->select_db(. ) in the helper function code).

Example 4: Caching

Our final example deals with caching of function return values. Usually you would want to cache resource-consuming calculations, database querying functions or other I/O related calls. Similar to previously mentioned helper functions, createCache() accepts callback function in $cb parameter. This callback function represents a computation for which we want to cache return values. Helper function finally returns a completely new anonymous function, which can then be used by outer code as a caching function.

Helper function

function createCache(callable $cb, bool $multiArgs = false)  $cache = []; if (!$multiArgs)  return function ($argument) use (&$cache, $cb)  if (array_key_exists($argument, $cache)) return $cache[$argument]; else  $cache[$argument] = $cb($argument); return $cache[$argument]; > >; > else  return function (. $args) use (&$cache, $cb)  $valFound = false; foreach ($cache as list($args1, $val1))  if ($args1 === $args)  $val = $val1; $valFound = true; break; > > if ($valFound) return $val; else  $val = $cb(. $args); $cache[] = [$args, $val]; return $val; > >; > >; 

Helper function first creates $cache array, which will serve as a storage for cached return values. Then it returns an anonymous function which executes a given callback $cb and caches its return value, but only if it does not find its return value already stored in the cache. Returned anonymous function could have been created in two branches, which is only a performance tweak — return values of callback functions accepting only one argument can be cached more efficiently, which is what the first branch is for.

Usage

We will define getPerson() function querying person’s data from the database and then we create caching function $getPersonCached() from it.

function getPerson ($id, $nameOnly = false)  echo "called widh id $id
"
; $person = selectFromTable("persons", $id); return $nameOnly ? $person["name"] : $person; > $getPersonCached = createCache("getPerson", true); $person1 = $getPersonCached("1"); $person2 = $getPersonCached("2"); $person1 = $getPersonCached("1"); // Outputs: // called with id 1 // called with id 2

As you see, repeated call to $getPersonCached() with argument «1» hasn’t invoked getPerson() function, because the return value has been obtained from the cache. If you wanted to make calls to getPerson() with the optional parameter $nameOnly changing, you would have to call createCache() with parameter $multiArgs set to TRUE .

$getPersonCache = createCache("getPerson", true); $person1 = $getPersonCache("1"); $personName1 = $getPersonCache("1", true); 

NOTE: We have used string-based callback «getPerson» as an argument for createCache() function in this examples, but you could naturally use anonymous function callbacks as well.

Conclusion

Источник

Php callback function this

Callback-функции как объекты первого класса представлены в PHP 8.1.0 как способ создания анонимных функций из callback-функций. Синтаксис заменяет существующий синтаксис вызова с использованием строк и массивов. Преимущество синтаксиса заключается в том, что он доступен для статического анализа и использует область видимости в точке, где получена callback-функция.

Синтаксис CallableExpr(. ) используется для создания объекта Closure из callback-функции. CallableExpr принимает любое выражение, которое может быть вызвано напрямую в грамматике PHP:

Пример #1 Простой пример callback-функции как объекты первого класса

class Foo public function method () <>
public static function staticmethod () <>
public function __invoke () <>
>
$obj = new Foo ();
$classStr = ‘Foo’ ;
$methodStr = ‘method’ ;
$staticmethodStr = ‘staticmethod’ ;
$f1 = strlen (. );
$f2 = $obj (. ); // вызываемый объект
$f3 = $obj -> method (. );
$f4 = $obj -> $methodStr (. );
$f5 = Foo :: staticmethod (. );
$f6 = $classStr :: $staticmethodStr (. );
// традиционная callback-функция с использованием строки, массива
$f7 = ‘strlen’ (. );
$f8 = [ $obj , ‘method’ ](. );
$f9 = [ Foo ::class, ‘staticmethod’ ](. );
?>

Замечание:

. является частью синтаксиса, а не пропуском.

У CallableExpr(. ) та же семантика, что и у Closure::fromCallable() . То есть, в отличие от callback-функции с использованием строк и массивов, CallableExpr(. ) учитывает область видимости в точке, где она создаётся:

Пример #2 Сравнение области действия CallableExpr(. ) и традиционной callback-функции

class Foo public function getPrivateMethod () return [ $this , ‘privateMethod’ ];
>
private function privateMethod () echo __METHOD__ , «\n» ;
>
>
$foo = new Foo ;
$privateMethod = $foo -> getPrivateMethod ();
$privateMethod ();
// Fatal error: Call to private method Foo::privateMethod() from global scope
// Это потому, что вызов выполняется вне Foo, и с этого момента будет проверяться видимость.
class Foo1 public function getPrivateMethod () // Использует область, в которой получена callback-функция.
return $this -> privateMethod (. ); // идентично Closure::fromCallable([$this, ‘privateMethod’]);
>
private function privateMethod () echo __METHOD__ , «\n» ;
>
>
$foo1 = new Foo1 ;
$privateMethod = $foo1 -> getPrivateMethod ();
$privateMethod (); // Foo1::privateMethod
?>

Замечание:

Создание объекта с помощью этого синтаксиса (например, new Foo(. ) ) не поддерживается, поскольку синтаксис new Foo() не считается callback-функцией.

Замечание:

Callback-функции как объекты первого класса нельзя комбинировать с оператором Nullsafe. Оба следующих результата приводят к ошибке времени компиляции:

Источник

Читайте также:  Javascript check this box
Оцените статью