Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[DI] Allow to count on lazy collection arguments#21455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
[DI] Allow to count on lazy collection arguments#21455
Uh oh!
There was an error while loading.Please reload this page.
Conversation
| * @param callable $generator | ||
| * @param int|null $count If provided, used as the returned value for count. iterator_to_array will be used otherwise. | ||
| */ | ||
| publicfunction__construct(callable$generator,$count =null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
As this class is internal and used only for this purpose, I think I can drop the$count = null behavior, though.
| publicfunctioncount() | ||
| { | ||
| if (null ===$this->count) { | ||
| returncount(iterator_to_array($this->getIterator())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
iterator_count($this->getIterator()) instead?
ogizanagiJan 29, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
👍 (But I'm sure we don't keep this behavior anyway ^^' (#21455 (comment)))
chalasr commentedJan 29, 2017
I would not add the |
ogizanagi commentedJan 29, 2017
@chalasr: calling For instance, in#21450, calling |
| * @param callable $generator | ||
| * @param int|null $count If provided, used as the returned value for count. iterator_to_array will be used otherwise. | ||
| */ | ||
| publicfunction__construct(callable$generator,$count =null) |
nicolas-grekasJan 29, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Aren't we always able to have the count? If yes, I'd make count mandatory and simplify thecount() method.
ogizanagiJan 29, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yes, it confirms#21455 (comment) (I'll remove this)
nicolas-grekas commentedJan 29, 2017
Wait, we can't! There maybe be conditional "yield", when |
nicolas-grekas commentedJan 29, 2017
Let's close and tweak the error message instead sorry for the bad suggestion. |
ogizanagi commentedJan 29, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@nicolas-grekas : But this case can be properly handled, right? Seehttps://github.com/ogizanagi/symfony/blob/3dfcbe10ac3aab14922b92afb0818d35cfa8ba8c/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php#L344 |
nicolas-grekas commentedJan 29, 2017
That's wise :) |
ogizanagi commentedJan 30, 2017
Ready to review |
chalasr commentedJan 30, 2017
LGTM 👍 |
| $parameterBag =$this->getParameterBag(); | ||
| $count =0; | ||
| foreach ($value->getValues()as$k =>$v) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
can be wrapped in a closure as second arg below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Indeed 👍
| $code =array(); | ||
| $code[] ='new RewindableGenerator(function() {'; | ||
| foreach ($value->getValues()as$k =>$v) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
$v is nice, makes the diff easier to review also
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
$v is nice, but a need to exploit$value again for conditionals count.$v is overwritten by:
$v =$this->wrapServiceConditionals($value, sprintf(" yield %s => %s;\n",$this->dumpValue($k,$interpolate),$this->dumpValue($value,
Can use something else for this though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Seecfdc528
| } | ||
| } | ||
| ($c =$this->getServiceConditionals($value)) ?$operands[] ="(int) ($c)" : ++$operands[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
when there are several conditionals, this will always evaluate to 1, isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
If there are several conditions, we'll get something like:
(int) ($this->has('foo') &&$this->has('other'))
for a single argument, so should be ok, right? (Actually I don't even know why you would have several conditions for a single service. In case of a collection of service all being ignored on invalid reference?)
nicolas-grekasJan 30, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
there are two cases:
- two optional lines in the list of values: these should count from zero to two condionally
- a single line with two contitionals inside (eg
- [ @?foo, @?bar ]: these count for zero or one only of course
ad both can be mixed, this one counting from zero to two also, (one per line):
-[ '@?foo1', '@?bar1' ]-[ '@?foo2', '@?bar2' ]
| } | ||
| } | ||
| ++$count; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
missing return statement?
ogizanagiJan 30, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Grumpf. Good catch. 😅
I need to add a test case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
| } | ||
| } | ||
| ($c =$this->getServiceConditionals($v)) ?$operands[] ="(int) ($c)" : ++$operands[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
can you move this line before calling wrapServiceConditionals and remove the need for the$y variable?
| returnsprintf('array(%s)',implode(',',$code)); | ||
| }elseif ($valueinstanceof IteratorArgument) { | ||
| $countCode =array(); | ||
| $countCode[] ='function() {'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
There should be a space betweenfunction and() to be valid with PSR-2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I did first. But any function generated in the dumped container by the PhpDumper givesfunction() currently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
then you can fix it in this PR also :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I'll rather do a PR on 2.7 to fix other occurrences (if there is in this branch, didn't check yet), don't you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Ok. There isn't any (appart from 3.3). I'll do it here 😆
| $code =implode("\n",array_map(function ($line) {return$line ?''.$line :$line; },explode("\n",$code))); | ||
| returnsprintf(" if (%s) {\n%s }\n",implode(' &&',$conditions),$code); | ||
| returnsprintf('%s',implode(' &&',$conditions)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
return implode(' && ', $conditions);?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Ah ah. Sure 😆
Thanks
nicolas-grekas commentedJan 31, 2017
👍 |
| publicfunctioncount() | ||
| { | ||
| if (is_callable($count =$this->count)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Do we need the local$count variable here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
we need it as calling$this->count() would fail below, but could be declared inside the if indeed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
No thinking about this again I would keep it as is.
xabbuh left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
👍
| $code[] ='new RewindableGenerator(function() {'; | ||
| $code[] ='new RewindableGenerator(function() {'; | ||
| foreach ($value->getValues()as$k =>$v) { | ||
| ($c =$this->getServiceConditionals($v)) ?$operands[] ="(int)($c)" : ++$operands[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Shouldn't there be a space after theint type cast?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
You're right. It's in the symfony rules. I don't know why I reverted this.
stof commentedJan 31, 2017
👍 |
nicolas-grekas commentedFeb 2, 2017
Thank you@ogizanagi. |
…anagi)This PR was merged into the 3.3-dev branch.Discussion----------[DI] Allow to count on lazy collection arguments| Q | A| ------------- | ---| Branch? | master| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets |#21450 (comment)| License | MIT| Doc PR | todo (withsymfony/symfony-docs#7336)When using the new iterator feature of the DI component to lazy load collection, we always know the number of arguments in the collection (only the invalidBehavior set to `IGNORE_ON_INVALID_REFERENCE` may change this number). So we are able to generate and use a `RewindableGenerator` implementing `\Countable` by computing this value ahead.So, in a service accepting `array|iterable`, like in the `GuardAuthenticationListener` (see#21450):```phpclass GuardAuthenticationListener implements ListenerInterface{ private $guardAuthenticators; /** *@param iterable|GuardAuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationProvider *@param LoggerInterface $logger A LoggerInterface instance */ public function __construct($guardAuthenticators, LoggerInterface $logger = null) { // ... } public function handle(GetResponseEvent $event) { if (null !== $this->logger) { $context = array() if (is_array($this->guardAuthenticators) || $this->guardAuthenticators instanceof \Countable) { $context['authenticators'] = count($this->guardAuthenticators); } $this->logger->debug('Checking for guard authentication credentials.', $context); } // ... }}```we still keep the ability to call count without loosing the lazy load benefits.Commits-------f23e460 [DI] Allow to count on lazy collection arguments
Uh oh!
There was an error while loading.Please reload this page.
When using the new iterator feature of the DI component to lazy load collection, we always know the number of arguments in the collection (only the invalidBehavior set to
IGNORE_ON_INVALID_REFERENCEmay change this number). So we are able to generate and use aRewindableGeneratorimplementing\Countableby computing this value ahead.So, in a service accepting
array|iterable, like in theGuardAuthenticationListener(see#21450):we still keep the ability to call count without loosing the lazy load benefits.