-
Notifications
You must be signed in to change notification settings - Fork 235
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Default property with @NamedArgumentConstructor #402
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,8 +15,10 @@ | |
|
||
use function array_keys; | ||
use function array_map; | ||
use function array_values; | ||
use function class_exists; | ||
use function constant; | ||
use function count; | ||
use function defined; | ||
use function explode; | ||
use function gettype; | ||
|
@@ -607,7 +609,7 @@ class_exists(NamedArgumentConstructor::class); | |
|
||
// choose the first property as default property | ||
$metadata['default_property'] = reset($metadata['properties']); | ||
} elseif (PHP_VERSION_ID < 80000 && $metadata['has_named_argument_constructor']) { | ||
} elseif ($metadata['has_named_argument_constructor']) { | ||
foreach ($constructor->getParameters() as $parameter) { | ||
$metadata['constructor_args'][$parameter->getName()] = [ | ||
'position' => $parameter->getPosition(), | ||
|
@@ -863,17 +865,36 @@ private function Annotation() | |
); | ||
} | ||
|
||
$defaultProperty = 'value'; | ||
// Change the default property only if the @NamedArgumentConstructor | ||
// tag and the default_property are set | ||
$arguments = $this->MethodCall(); | ||
|
||
$positionalArguments = $arguments['positional_arguments'] ?? []; | ||
$namedArguments = $arguments['named_arguments'] ?? []; | ||
|
||
if ( | ||
self::$annotationMetadata[$name]['has_named_argument_constructor'] | ||
&& self::$annotationMetadata[$name]['default_property'] !== null | ||
) { | ||
$defaultProperty = self::$annotationMetadata[$name]['default_property']; | ||
} | ||
$values = $namedArguments; | ||
foreach (self::$annotationMetadata[$name]['constructor_args'] as $property => $parameter) { | ||
$position = $parameter['position']; | ||
if (isset($values[$property]) || ! isset($positionalArguments[$position])) { | ||
continue; | ||
} | ||
|
||
$values[$property] = $positionalArguments[$position]; | ||
} | ||
} else { | ||
$values = $namedArguments; | ||
if (! empty($positionalArguments) && ! isset($values['value'])) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use count instead, empty does not communicate intent well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but the output of this code is usually cached and even if not, this is not a tight loop There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wanted to toy with phpbench so I build a little benchmark from this raw benchmark: <?php
class ArrayCheckerBench
{
public function provideArrays(): \Generator
{
yield 'empty array' => ['array' => []];
yield 'huge array' => ['array' => range(0, 100000)];
}
public function checkArrayWithEmpty(array $x): bool
{
return empty($x);
}
public function checkArrayWithCount(array $x): bool
{
return count($x) === 0;
}
/**
* @Revs(1000000)
* @Iterations(5)
* @ParamProviders({"provideArrays"})
*/
public function benchCheckIfArrayIsEmptyWithEmpty(array $parameters): void
{
$this->checkArrayWithEmpty($parameters['array']);
}
/**
* @Revs(1000000)
* @Iterations(5)
* @ParamProviders({"provideArrays"})
*/
public function benchCheckIfArrayIsEmptyWithCount(array $parameters): void
{
$this->checkArrayWithCount($parameters['array']);
}
} Here are the results:
Looks like count takes almost 10% more time, so in relative terms, it's far better indeed. In absolute terms though, it seems to be 30 ns slower… I don't think we should worry about such small differences. |
||
if (count($positionalArguments) === 1) { | ||
$value = $positionalArguments[0]; | ||
} else { | ||
$value = array_values($positionalArguments); | ||
} | ||
|
||
$values = $this->MethodCall($defaultProperty); | ||
$values['value'] = $value; | ||
} | ||
} | ||
|
||
if (isset(self::$annotationMetadata[$name]['enum'])) { | ||
// checks all declared attributes | ||
|
@@ -1027,7 +1048,7 @@ private function Annotation() | |
* @throws AnnotationException | ||
* @throws ReflectionException | ||
*/ | ||
private function MethodCall(string $defaultProperty): array | ||
private function MethodCall(): array | ||
{ | ||
$values = []; | ||
|
||
|
@@ -1038,7 +1059,7 @@ private function MethodCall(string $defaultProperty): array | |
$this->match(DocLexer::T_OPEN_PARENTHESIS); | ||
|
||
if (! $this->lexer->isNextToken(DocLexer::T_CLOSE_PARENTHESIS)) { | ||
$values = $this->Values($defaultProperty); | ||
$values = $this->Values(); | ||
} | ||
|
||
$this->match(DocLexer::T_CLOSE_PARENTHESIS); | ||
|
@@ -1054,7 +1075,7 @@ private function MethodCall(string $defaultProperty): array | |
* @throws AnnotationException | ||
* @throws ReflectionException | ||
*/ | ||
private function Values(string $defaultProperty): array | ||
private function Values(): array | ||
{ | ||
$values = [$this->Value()]; | ||
|
||
|
@@ -1075,23 +1096,17 @@ private function Values(string $defaultProperty): array | |
$values[] = $value; | ||
} | ||
|
||
$namedArguments = []; | ||
$positionalArguments = []; | ||
foreach ($values as $k => $value) { | ||
if (is_object($value) && $value instanceof stdClass) { | ||
$values[$value->name] = $value->value; | ||
} elseif (! isset($values[$defaultProperty])) { | ||
$values[$defaultProperty] = $value; | ||
$namedArguments[$value->name] = $value->value; | ||
} else { | ||
if (! is_array($values[$defaultProperty])) { | ||
$values[$defaultProperty] = [$values[$defaultProperty]]; | ||
} | ||
|
||
$values[$defaultProperty][] = $value; | ||
$positionalArguments[$k] = $value; | ||
} | ||
|
||
unset($values[$k]); | ||
} | ||
|
||
return $values; | ||
return ['named_arguments' => $namedArguments, 'positional_arguments' => $positionalArguments]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All right, thank you for clarifying. 👍🏻 |
||
} | ||
|
||
/** | ||
|
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.
Could you extract this block into a private helper please?
Method name could be better
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.
Updated!