1

Considering this example from Slim PHP, which is used as middleware.

What's the difference between this,

$authenticateForRole = function ( $role = 'member' ) {
    return function () use ( $role ) {
        $user = User::fetchFromDatabaseSomehow();
        if ( $user->belongsToRole($role) === false ) {
            $app = \Slim\Slim::getInstance();
            $app->flash('error', 'Login required');
            $app->redirect('/login');
        }
    };
};    

and this,

$authenticateForRole = function ( $role = 'member' ) {
    $user = User::fetchFromDatabaseSomehow();
    if ( $user->belongsToRole($role) === false ) {
        $app = \Slim\Slim::getInstance();
        $app->flash('error', 'Login required');
        $app->redirect('/login');
    }
};

Aren't those functions the same?

1
  • Should I close my account for asking this? Commented May 28, 2015 at 5:33

1 Answer 1

1

In the context of the slim framework and middleware, and the particular example this question is associated with.

The logic is wrapped in a closure so it can be called at later point by the framework middleware logic and preserve the user argument for the $role.

for reference and context - Usage code for from original post

$app->get('/foo', $authenticateForRole('admin'), function () {
//Display admin control panel
});

understanding the calling context, you should see why these two are different.

from this point on when referring to the 2nd code you provided I will reference to it as $authenticateForRole2 in code.


case 1 - Fail

Using the 2nd code as shown below: will result in an immediate execution of the function $authenticateForRole2 the return value(null) will be passed as the middlewere argument. The "middlewere" argument is expected to be an callable/invokable object, and that is why this code is incorrect.

$app->get('/foo', $authenticateForRole2('admin'), function () {
//Display admin control panel
});

case 2 - lambada with no control over $role (~Works)

Partially Works, not 100% same functionality it will use the default $role as set in the declaration of the function. And you can't provide a different $role parameter, when defining the api(setting up the paths)

$app->get('/foo', $authenticateForRole2, function () {
//Display admin control panel
});

case 3 - repetition of declaration (Works but not recommended)

This should work but it will require repeating the declaration for each $role value. for example if one path is for 'admin' and the other is for 'member'

note I moved the $role inside the function, because slim pass an object as argument to the middlewere function when it is called.

$app->get('/foo', 
    function()  {  
        $role = 'admin'
        $user = User::fetchFromDatabaseSomehow();
        if ( $user->belongsToRole($role) === false ) {
            $app = \Slim\Slim::getInstance();
            $app->flash('error', 'Login required');
            $app->redirect('/login');
        }
} , function () {
//Display admin control panel
});

$app->get('/bar', 
    function (){  
        $role = 'member'
        $user = User::fetchFromDatabaseSomehow();
        if ( $user->belongsToRole($role) === false ) {
            $app = \Slim\Slim::getInstance();
            $app->flash('error', 'Login required');
            $app->redirect('/login');
        }
} , function () {
//Display admin control panel
});

case 4 ( original example )

The original example uses the closure wrapping trick to provide a DRY way for the role authentication method.

$app->get('/foo', $authenticateForRole('admin'), function () {
//Display admin control panel
});  

$app->get('/bar', $authenticateForRole('member'), function () {
//Display member control panel
});
Sign up to request clarification or add additional context in comments.

2 Comments

Sorry, but I still don't understand why authenticateForRole() couldn't be a normal function instead of an anonymous function that returns another anonymous function. Could you explain a little more your answer?
Thanks for your clarification. I was confused because I don't really know the internals and this example (mw1 and mw2) didn't return any values.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.