Is it possible to use $params in anonymous functions?
Closed this issue · 9 comments
Composer.json
"extra": {
"config-plugin": {
"params": [
"config/params.php",
"?config/params-local.php"
],
"web": [
"config/web.php"
]
}
}
params.php
return [
'app.name' => 'My Application',
];
web.php
return [
'app' => function () use($params) {
return [
'name' => $params['app.name']
];
},
'appName' => $params['app.name'],
];
index.php
require __DIR__.'/../vendor/autoload.php';
$config = require hiqdev\composer\config\Builder::path('web');
$appClosure = $config['app'];
$app = call_user_func($appClosure);
var_dump($app, $config['appName']);
Got:
php ./public/index.php
PHP Notice: Undefined variable: params in /home/razon/Projects/php/composer-config/vendor/hiqdev/composer-config-plugin-output/web.php on line 10
array(1) {
["name"]=>
NULL
}
string(14) "My Application"
BTW, the generated web.php missing use
language structure
$baseDir = dirname(dirname(dirname(__DIR__)));
defined('COMPOSER_CONFIG_PLUGIN_BASEDIR') or define('COMPOSER_CONFIG_PLUGIN_BASEDIR', $baseDir);
$_ENV = array_merge((array) require __DIR__ . '/dotenv.php', (array) $_ENV);
return array (
'app' => function () {
return [
'name' => $params['app.name']
];
},
'appName' => 'My Application',
);
Please, show what do you want in practice, cause your example doesn't look practical.
I am trying to access parameters in an anonymous function.
Such as logger configuration(DI), I want to make FileTarget's levels to be mergeable via params.php
and params-local.php
:
'logger' => function (yii\di\Container $container) {
$logger = new Yiisoft\Log\Logger([
$container->get(Yiisoft\Log\FileTarget::class),
]);
return $logger;
},
Yiisoft\Log\FileTarget::class => function (yii\di\Container $container) use($params) {
/** @var yii\base\Aliases $aliases */
$aliases = $container->get('aliases');
$target = new Yiisoft\Log\FileTarget(
$aliases->get($params['console.logger.target.file.logFile']),
$container->get(Yiisoft\Log\FileRotator::class)
);
$target->levels = $params['logger.target.file.levels'];
//...
return $target;
},
Yiisoft\Log\FileRotator::class => [
'__class' => Yiisoft\Log\FileRotator::class,
],
params.php
return [
'logger.target.file.levels' => ['warning', 'error'],
];
params-local.php
return [
'logger.target.file.levels' => ['info', 'debug'],
];
You can get params from the app object similarly you get aliases:
$target->levels = $container->get('app')->params['logger.target.file.levels'];
But it looks like a good case to improve Yii DI for these objects could be configured with arrays only without closures.
Something like this:
'logger' => [
'__class' => Logger::class,
'__construct' => [
[Reference::to('file-target')],
],
],
'file-target' => [
'__class' => Yiisoft\Log\FileTarget::class,
'__construct' => [
Reference::aliasTo('@logger/logFile'),
Reference::to(Yiisoft\Log\FileRotator::class),
],
'levels' => $params['logger.target.file.levels'],
],
I'll look into it on a weekend.
Your solution look good to me:)
EDIT:
I could not find the method Reference::aliasTo
(yiisoft/di), am I missing something?
Hi, I found another issue about exporting Closure
, here is an example of yii-demo.
I've read the code of Helper::dumpClosure
, but have no idea how to handle it so far.
It may can be fixed by two ways:
- Defines full qualified name in closure, such as
return new Yiisoft\Log\Logger([])
, simple, but strange. - Dump the
use
lines.
Reproduce:
$ ./vendor/bin/yii serve
$ curl http://localhost:8080
[Tue Jul 2 13:52:29 2019] PHP Fatal error: Uncaught Error: Class 'Logger' not found in /home/razon/Projects/yiisoft/yii-demo/vendor/hiqdev/composer-config-plugin-output/web.php:478
Stack trace:
#0 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/factory/src/Definitions/CallableDefinition.php(19): {closure}(Object(yii\di\Container), Array)
#1 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(128): Yiisoft\Factory\Definitions\CallableDefinition->resolve(Object(yii\di\Container), Array)
#2 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(116): yii\di\Container->buildInternal('logger', Array)
#3 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(84): yii\di\Container->build('logger', Array)
#4 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/factory/src/Definitions/Reference.php(45): yii\di\Container->get('logger')
#5 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(128): Yiisoft\Factory\Definitions\Reference->resolve(Object(yii\di\Container), Array)
# in /home/razon/Projects/yiisoft/yii-demo/vendor/hiqdev/composer-config-plugin-output/web.php on line 478
[Tue Jul 2 13:52:29 2019] [::1]:48260 [500]: / - Uncaught Error: Class 'Logger' not found in /home/razon/Projects/yiisoft/yii-demo/vendor/hiqdev/composer-config-plugin-output/web.php:478
Stack trace:
#0 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/factory/src/Definitions/CallableDefinition.php(19): {closure}(Object(yii\di\Container), Array)
#1 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(128): Yiisoft\Factory\Definitions\CallableDefinition->resolve(Object(yii\di\Container), Array)
#2 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(116): yii\di\Container->buildInternal('logger', Array)
#3 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(84): yii\di\Container->build('logger', Array)
#4 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/factory/src/Definitions/Reference.php(45): yii\di\Container->get('logger')
#5 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(128): Yiisoft\Factory\Definitions\Reference->resolve(Object(yii\di\Container), Array)
# in /home/razon/Projects/yiisoft/yii-demo/vendor/hiqdev/composer-config-plugin-output/web.php on line 478
Dump the use
lines is good but how? :)
I have no idea so far, it maybe impossible :(
That's actually a problem not about anonymous functions but about $params
is not defined in configs at all.
Initialization of $params
was added in configs.
So this problem is fixed. Just use as you expected from the very beginning:
In web.php
:
return [
'app' => function () use ($params) {
return [
'name' => $params['app.name']
];
},
'appName' => $params['app.name'],
];
Closing this issue. Please open a new one in case of any problems.