Jump to content

Passing variables to anonymous function


NotionCommotion

Recommended Posts

I think I am on the right track.

 

Slim has a Pimple container feature where a function could be added such as $container['logger'] = function($config) {/* ... */}; and within the callback, it could be used as $this->logger->addInfo('Hi!');.

 

I wish to create something similar, but instead it will create a factory object.  My difficulty I believe is passing the variables to the $this->factory().  What am I doing wrong?

 

One other thing I don't understand is how $config is getting to the logger function.  I would have thought that $config is global, and as such, I would need to do $container['logger'] = function() use $config {/* ... */};.   I appear to be incorrect as the logger script works as shown below, and would appreciate some clarification what is going on.

 

Thanks

$config=[/* settings */];
$app = new \Slim\App(["settings" => $config]);

$container = $app->getContainer();

$container['logger'] = function($config) {
    $logger = new \Monolog\Logger('my_logger');
    $file_handler = new \Monolog\Handler\StreamHandler("../logs/app.log");
    $logger->pushHandler($file_handler);
    return $logger;
};
$container['db'] = function($config) { /* settings */};
$container['account'] = function($config) { /* settings */};

$container['factory'] = function ($request,$slim) {
    return new \MyApp\factory($request,$slim);
};

$app->get('/configure', function (Request $request, Response $response) {
    $this->logger->addInfo('Hello world!');
    return $response->withJson($this->factory($request,$this)->get());
});
class factory
{
    private $request,$slim;

    public function __construct($request,$slim)
    {
        $this->request=$request;
        $this->slim=$slim;
    }
    public function createConfig()
    {
        return new \MyApp\Configure(['logger'=>$this->logger,'db'=>$this->db,'account'=>$this->account]);
    }    
    public function createDocument()
    {
        return new \MyApp\Document(['id'=>$this->request->getAttribute('id'),'logger'=>$this->logger,'db'=>$this->db,'account'=>$this->account]);
    }    
}
Link to comment
Share on other sites

The function you set on the container is passed an instance of the container as it's first parameter:

 

Pimple Documentation

Notice that the anonymous function has access to the current container instance, allowing references to other services or parameters.

If you want the global $config variable, you'd have to use it as you thought.

 

In the case of your factory function service, you need to either pass a function that returns the factory function, or use the protect helper method.

 

Because Pimple sees anonymous functions as service definitions, you need to wrap anonymous functions with the protect() method to store them as parameters:

$container['random_func'] = $container->protect(function () {
    return rand();
});

 

Link to comment
Share on other sites

Thanks Kicken,

 

I seem to be missing something with the Pimple approach.

 

Also, how would it look to pass a function that returns the factory function?

$app->get('/configure', function (Request $request, Response $response) {
    var_dump($this->random_func);
    echo("\n");
    var_dump($this->random_func());
    exit;
});
object(Closure)#26 (0) { }
Fatal error: Call to undefined method Slim\Container::random_func() in /var/www/src/public/index.php on line 166
Link to comment
Share on other sites

You can't call the factory function directly like that because PHP will not understand the code properly. $this->random_func is interpreted as 'Get me the random_func' property but $this->random_func() is interpreted as 'Call the random_func method'. Since the class doesn't have a random_func method you get the error.

 

What you need to do is first get the random_func property, then call it as a function. In PHP 7 you can use parenthesis to force the proper interpretation:

($this->random_func)();
For older PHP versions you have to either use a variable or call_user_func.

$random_func = $this->random_func;
$random_func();

//or

call_user_func($this->random_func);
Link to comment
Share on other sites

Thanks kicken,

 

I guess I kind of knew that, but your excellent explanation made it sink in.

 

Below is what I ended up doing.

$container['factory'] = $container->protect(function ($request,$slim) {
    return new Factory($request,$slim);
});

$app->get('/configure', function (Request $request, Response $response) {
    return $response->withJson(call_user_func($this->factory,$request,$this)->createConfig()->get());
});

If I decided not to use the Pimple protect method and instead pass a function, would it just be the following with the other part the same?

$container['factory'] = $container->protect(function ($request,$slim) {
    return function($request,$slim) {new Factory($request,$slim);};
});
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.