note 121207 deleted from class.closure by cmb

From: Date: Mon, 11 Mar 2019 13:34:26 +0000
Subject: note 121207 deleted from class.closure by cmb
References: 1  Groups: php.notes 
Request: Send a blank email to php-notes+get-210353@lists.php.net to get a copy of this message
Note Submitter: centurianii at yahoo dot co dot uk ---- The problem: a function that calls another function which is passed in the arguments of the initial function. The callable might re-use the arguments of the initial function. Whatever the callable is we want a simple function for use in our code (here is where closure comes). Example: a generic Header class that sends files (cached, not cached, for download, inline etc.). Probably readfile() is all you need right? But what when a captcha library has a function output() that you want to be used in the place of readfile()? No big deal you might say, pass a callable in the function's arguments, but let's unwind the possibilities of the callable argument: 1. it's another function in this scope, 2. it's a class method, 3. it's a static method of a class. Php uses different helpers to call this argument-function: 1. call_user_func_array(), 2, 3. call_user_func_array() or Reflection. A generic solution that exploits most of php's advanced features: closures, callables, Reflection. /** * @param string $file The path of a file * @param ... more specific arguments here ... * @param string[] $call A hashed array that contains the function we want to * operate on our arguments and follows some rules as follows * -key 'class': the class name the function belongs to or null, * -key 'construct': the class's arguments on construction or null, * -key 'args': an array of arguments explicit for the callable or null, * -key 'callable': the name of the function (null not allowed). */ function generic($file = null, $call = array('callable' => '\readfile')) { if (isset($call['class'])) { // a closure... $action = function() use ($call) { $method = new \ReflectionMethod($call['class'], $call['callable']); if ($method->isStatic()) { // YOU decide what to do with the arguments in generic() if (isset($call['args'])) { $method->invokeArgs(null, $call['args']); } else { $method->invoke(null); } } else { $obj = new \ReflectionClass($call['class']); if (isset($call['construct'])) { $obj->newInstanceArgs($call['construct']); } else { $obj->newInstance(); } // YOU decide what to do with the arguments in generic() if (isset($call['args'])) { $method->invokeArgs($obj, $call['args']); } else { $method->invoke($obj); } } }; } else { // another closure... $action = function() use ($call, $file) { // YOU decide what to do with the arguments in generic() if (isset($call['args'])) { \call_user_func_array($call['callable'], $args); } else { \call_user_func_array($call['callable'], array($file)); } }; } // ...some commands here... \header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); \header("Cache-Control: no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0"); \header("Content-Description: File Transfer"); \header("Content-Disposition: inline; filename=\"" . $file . "\""); \header("Content-Type: image/jpeg"); // adjust the following... \header('Content-Length: ' . \filesize($file)); // see how we use a closure $action(); } // let's call the generic() generic('client/assets/404.jpg'); Just an example use of closures...

« previous php.notes (#210353) next »