Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[ExpressionLanguage] Create an ExpressionFunction from a PHP function name#21122
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
Uh oh!
There was an error while loading.Please reload this page.
Conversation
| * | ||
| * @author Dany Maillard <danymaillard93b@gmail.com> | ||
| */ | ||
| class ExpressionPhpFunctionextends ExpressionFunction |
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 can make simple named constructor inExpressionFunction rather than utilizing inheritance:
ExpressionFunction::php('strtoupper')
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 like this suggestion of using a factory instead of a new class
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.
Done
stof commentedJan 6, 2017
Does it work for namespaced functions ? I think it does not in case they don't have the leading |
| * | ||
| * @throws \InvalidArgumentException if given function name does not exist | ||
| */ | ||
| publicstaticfunctionphp($name) |
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.
What about a more expressive name likefromPhp?
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's better. I done.
maidmaid commentedJan 7, 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.
@stof Indeed, for namespaced functions, it's doesn't work; a |
maidmaid commentedJan 7, 2017
@stof An another solution would be don't throw exception, to evaluate with short name of namespaced function and to compile with full name of namespaced function. |
stof commentedJan 9, 2017
A syntax error ? Which error are you talking about ? Are you trying to put the namespace in the ExpressionLanguage function name too ? This is not supported, as EL does not have namespaced functions. The alternative is to decide than namespaced PHP functions are unsupported, but I would throw an exception early in this case, saying that EL function names cannot use |
fabpot commentedJan 9, 2017
I think supporting namespaced functions is better and having a second argument to change the function name in EL sounds like a good idea anyway, even for regular functions. |
maidmaid commentedJan 10, 2017
| thrownew \InvalidArgumentException(sprintf( | ||
| 'An expression function name must be defined if PHP function "%s" is in namespace.', | ||
| $phpFunction | ||
| )); |
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.
should be on one line
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.
Done.
| } | ||
| $reflection =new \ReflectionFunction($phpFunction); | ||
| if ($reflection->inNamespace() && !$expressionFunction) { |
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.
Instead of using reflection, what about just checking for\\ in the function name?
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.
And I will move the second part!$expressionFunction first to make it faster.
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.
Reflection is more expressive that\\ and is anyway used further.
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 moved!$expressionFunction at first.
| * @throws \InvalidArgumentException if given PHP function name is in namespace | ||
| * and expression function name is not defined | ||
| */ | ||
| publicstaticfunctionfromPhp($phpFunction,$expressionFunction =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.
Doesn't Symfony have some convention to put factories/named constructors before the real constructor? I'm not sure, just asking.
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,__construct() is always first
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 had to read the PHP doc to know what is expressionFunction. I would rename it toexpressionFunctionName or something else.
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.
For clarity, I renamedexpressionFunction toexpressionFunctionName andphpFunction tophpFunctionName.
lyrixx commentedJan 22, 2017
@maidmaid could you update the PR description to match the new API? |
maidmaid commentedJan 24, 2017
@lyrixx Yes, I updated the PR description now. |
| $reflection =new \ReflectionFunction($phpFunctionName); | ||
| if (!$expressionFunctionName &&$reflection->inNamespace()) { | ||
| thrownew \InvalidArgumentException(sprintf('An expression function name must be defined if PHP function "%s" is in namespace.',$phpFunctionName)); |
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.
An expression function name must be defined when PHP function "%s" is namespaced.?
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.
Done
nicolas-grekas 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.
👍 with minor comment
maidmaid commentedFeb 16, 2017
It's done@nicolas-grekas :) |
fabpot commentedFeb 16, 2017
Apparently, tests are broken when applying these changes. |
maidmaid commentedFeb 19, 2017
I fixed tests@fabpot. |
fabpot commentedFeb 19, 2017
@maidmaid I'm still not convinced that using reflection is needed. Here is my patch to get rid of it: diff --git a/src/Symfony/Component/ExpressionLanguage/ExpressionFunction.php b/src/Symfony/Component/ExpressionLanguage/ExpressionFunction.phpindex d011854804..87a494f82d 100644--- a/src/Symfony/Component/ExpressionLanguage/ExpressionFunction.php+++ b/src/Symfony/Component/ExpressionLanguage/ExpressionFunction.php@@ -77,18 +77,16 @@ class ExpressionFunction */ public static function fromPhp($phpFunctionName, $expressionFunctionName = null) {+ $phpFunctionName = ltrim($phpFunctionName, '\\'); if (!function_exists($phpFunctionName)) { throw new \InvalidArgumentException(sprintf('PHP function "%s" does not exist.', $phpFunctionName)); }- $reflection = new \ReflectionFunction($phpFunctionName);- if (!$expressionFunctionName && $reflection->inNamespace()) {+ $parts = explode('\\', $phpFunctionName);+ if (!$expressionFunctionName && count($parts) > 1) { throw new \InvalidArgumentException(sprintf('An expression function name must be defined when PHP function "%s" is namespaced.', $phpFunctionName)); }- $phpFunctionName = $reflection->getName();- $expressionFunctionName = $expressionFunctionName ?: $reflection->getShortName();- $compiler = function () use ($phpFunctionName) { return sprintf('\%s(%s)', $phpFunctionName, implode(', ', func_get_args())); };@@ -99,6 +97,6 @@ class ExpressionFunction return call_user_func_array($phpFunctionName, array_splice($args, 1)); };- return new self($expressionFunctionName, $compiler, $evaluator);+ return new self($expressionFunctionName ?: $parts[count($parts) - 1], $compiler, $evaluator); } } Any downsides? |
fabpot commentedFeb 20, 2017
@maidmaid Can you submit a PR on the docs to document this new feature? |
fabpot commentedFeb 20, 2017
Thank you@maidmaid. |
maidmaid commentedFeb 21, 2017
Thank you to you@fabpot and others reviewers. I created doc PR. |
…hp (maidmaid, javiereguiluz)This PR was merged into the master branch.Discussion----------[ExpressionLanguage] Document ExpressionFunction::fromPhpcfsymfony/symfony#21122Commits-------415c4ec Update extending.rst478400a Minor reword059155f Add versionadded6c9e09d Fix typoc70ea7f Fix typo6d9af37 Add fromPhp tip
Uh oh!
There was an error while loading.Please reload this page.
When weextend Expression Language, we often need to add PHP functions whose code is repetitive and redundant at the compiler/evaluator level. This PR proposes a new way more generic which allows to add a PHP function.
currently:
with this PR:
It includes PHP namespaced function: