phpclosuresanonymous-functionphp-closures

Refactoring closures/anonymous functions in PHP


Is it possible to refactor the anonymous function out of code like this:

function foo($path, $callback) {
    $callback();
}

$app = array('a', 'b', 'c');

foo('vehicle/:id', function() use ($app) {
    echo $app[0];
});

I tried this but it did not echo anything:

function foo($path, $callback) {
    $callback();
}

$vehicleCallback = function() use ($app) {
    echo $app[0];
};

$app = array('a', 'b', 'c');

foo('vehicle/:id', $vehicleCallback);

Other variations gave me syntax errors. I am looking to move the functions into a separate file, if that matters.

This is my end goal

callbacks.php

$cb1 = function () use ($app) {
    // things
};

$cb2 = function () use ($app) {
    // things
};

// ...more callbacks

router.php

require 'callbacks.php';

$app = new \Foo();

// code that might possibly manipulate $app

$app->bar('/some/relative/path/:param1', $cb1);
$app->bar('/another/relative/path', $cb2);

// possibly more code that mutates $app and then more callbacks

Solution

  • You should definitely turn on error_reporting:

    Notice: Undefined variable: app in ... on line 6

    When you move line:

    $app = array('a', 'b', 'c');
    

    at the beginning of your script you'll get result a

    EDIT

    You can use $app this way:

    <?php
    
    function foo($path, $callback, $app) {
        $callback($app);
    };
    
    $vehicleCallback = function($app) {
        echo $app[0];
    };
    
    $app = array('a', 'b', 'c');
    
    foo('vehicle/:id', $vehicleCallback, $app);
    

    EDIT2

    Sample code for your class

    <?php
    
    $cb1 = function ($app, $path) {
        // things
        $app->display('cb1 '.$path.'<br />');
    };
    
    $cb2 = function ($app, $path) {
        // things
        $app->display('cb2 '.$path);
    };
    
    
    class Foo {
        public function display ($string) {
            echo strtoupper($string);
        }
    
        public function bar ($path, $closure) {
            $closure($this, $path);
        }
    }
    
    
    $app = new \Foo();
    
    // code that might possibly manipulate $app
    
    $app->bar('/some/relative/path/:param1', $cb1);
    $app->bar('/another/relative/path', $cb2);
    
    // possibly more code that mutates $app and then more callbacks