Skip to content

[Yaml] Added support for parsing PHP constants #18626

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

Merged
merged 2 commits into from
Jun 23, 2016

Conversation

HeahDude
Copy link
Contributor

@HeahDude HeahDude commented Apr 24, 2016

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets ~
License MIT
Doc PR TODO

@HeahDude
Copy link
Contributor Author

I was reading http://symfony.com/doc/current/components/dependency_injection/parameters.html#constants-as-parameters and felt sad about the note for yaml support.

Is this PR acceptable? Does this need a flag? Or to be reversible (which does not seem doable)?

There is no sense to handle such case with the dumper imho (unless it is passed as a string?? but what would be the use case?).

@hhamon
Copy link
Contributor

hhamon commented Apr 24, 2016

I'm -1 for such horrible hacks. YAML is not a suitable format to handle metada like describing a thing is a constant.

@xabbuh
Copy link
Member

xabbuh commented Apr 24, 2016

Usually I would agree with @hhamon and I had the same feeling when reading the headline of this PR. But on the other hand @fabpot always wanted to have the Yaml component to support the things we need for Symfony (i.e. being able to configure the framework) instead of supporting the full YAML specs. Now, this is something that is supported by other configuration formats (i.e. PHP and XML), but which isn't supported for the YAML config format. Thus, I am 👍 for closing the gap.

@@ -562,6 +562,8 @@ private static function evaluateScalar($scalar, $flags, $references = array())
}

return;
case 0 === strpos($scalar, '!php/const:'):
return @constant(substr($scalar, 11));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should to throw a ParseException here if the constant does not exist (or at least do that when the PARSE_EXCEPTION_ON_INVALID_TYPE flag is set).

Copy link
Contributor Author

@HeahDude HeahDude Apr 24, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, I first did it because this flag looks indeed appropriate. I don't know why I've reverted it.

So I'll push it quickly :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, now that I think of this again, I do not think we should evaluate the flag for this. Such an error imo should never be silenced.

Copy link
Contributor Author

@HeahDude HeahDude Apr 24, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not an error, it's a warning, preventing to get null, remove the @ and the last test fails because it gets 0.0 instead of null. That's why I silenced it (and removed the flag in the process without giving it a second thought).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that this usually indicates a mistake made by the developer when writing the YAML file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I now see you answered before me, I maintain my proposal though, but I'm not against yours.

Still I would rather not add a new flag for this, the goal here is to ease configuration ; currently you need to import an xml or a php file while yaml is very common (I think and always used it only).

So needing to add a flag does not seem to "keep it easy" while using PARSE_EXCEPTION_ON_INVALID_TYPE looks more like "keep doing as usual, just pass a constant if you want".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HeahDude Well, for the configuration of services the users would not have to do that. It's the responsibility of us to set up the parser properly in the YamlFileLoader. So we are more talking about someone who uses the parser in their own code.

Copy link
Contributor Author

@HeahDude HeahDude Apr 24, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood! So I need to:

  1. add a flag like PARSE_PHP_CONSTANTS in Yaml class
  2. either throw a ParseException or return null when the constant does not exist
    maybe using PARSE_EXCEPTION_ON_INVALID_TYPE
  3. add the flag PARSE_PHP_CONSTANTS to YamlFileLoader config.

Is that correct? What about point 2?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. And I think as you would then have to deliberately turn on the feature, throwing an exception when a constant does not exist is the right way.

Copy link
Contributor Author

@HeahDude HeahDude Apr 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm almost there :)

Since the constant are not autoloaded (IIUC), one may expect to get null if a constant is not defined in an environment, so I guess we can take advantage of the triggered E_WARNING (ref http://php.net/manual/en/function.constant.php) as it will be shown as a silenced error in the profiler thanks to #16760.

Hence, I suggest we only trigger an exception when PARSE_EXCEPTION_ON_INVALID_TYPE flag is passed.

EDIT then it could be up to the user to test null !== $constant when no exception is thrown(?)

I already did such implementation but I've got an issue when the constant is not "inlined":

foo:
    - '!php/const:PHP_INT_MAX' # does not work
bar: ['!php/const:PHP_INT_MAX'] # works
baz: { foo: '!php/const:PHP_INT_MAX' } # works

I think it comes from the Parser as I only changed the Inline class for now, any lead ?

Thanks.

@linaori
Copy link
Contributor

linaori commented Apr 24, 2016

I would be really happy to see this implemented. I prefer yaml over xml by a lot for non-public packages, but not having constants is a big limitation to yaml :(

@HeahDude HeahDude force-pushed the feature/yaml-php-const branch from 4f0835c to a58d960 Compare April 25, 2016 09:36
3.2.0
-----

* added support for PHP constants in yaml configuration files
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YAML

@HeahDude HeahDude force-pushed the feature/yaml-php-const branch 2 times, most recently from 09134dc to 06fcb9f Compare April 25, 2016 13:03
@HeahDude
Copy link
Contributor Author

Ok, comments addressed, tests are green :)

I guess the failure on low depth will have to wait for master to point on 3.2.

@dunglas
Copy link
Member

dunglas commented Apr 29, 2016

Supporting PHP constants would be nice but the proposed syntax !php/const:PHP_INT_MAX is not intuitive and looks ugly. Can we have another nicer syntax?

@HeahDude
Copy link
Contributor Author

@dunglas suggestions are welcome! It actually matches the object syntax !php/object, so I thought it would be both consistent and easy to learn. Have you something else in mind?

@HeahDude
Copy link
Contributor Author

Could be like float or binary !! constant PHP_INT_MAX.

@@ -562,6 +564,15 @@ private static function evaluateScalar($scalar, $flags, $references = array())
}

return;
case 0 === strpos($scalar, '!php/const:'):
if (self::$constantSupport) {
return @constant(substr($scalar, 11));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

receiving null when a constant does not exist makes debugging very hard when you make a typo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stof there is a hidden conversation on a diff above between me and @xabbuh where we argue about this. It returns null but there is a warning logged as silenced error thanks to #16760.
Isn't that enough? Maybe we could also silence it in master for the XmlLoader?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, IMO, we should not silence things here

Copy link
Contributor Author

@HeahDude HeahDude Apr 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be consistent with the current XmlLoader indeed. But null will be returned anyway with an E_WARNING.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't we trigger an exception when the const is not defined? Would look better to me ATM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to distinguish null when assigned to a constant from when it's not defined?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, using defined()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK great! Then we should do it indeed. What do others think? @xabbuh @stof

@stof
Copy link
Member

stof commented Apr 29, 2016

Could be like float or binary !! constant PHP_INT_MAX.

no it cannot. !!float is part of the Yaml standard. custom tags must star with a single !, not 2

@HeahDude
Copy link
Contributor Author

Ok, so why not !constant PHP_INT_MAX? Although I'm not against the current syntax.

@xabbuh
Copy link
Member

xabbuh commented Apr 29, 2016

I would not change the tag name. The php: part acts like a Namespace here which reduces the risk to conflict with custom tags from other libraries.

@dunglas
Copy link
Member

dunglas commented Apr 29, 2016

@xabbuh it makes perfectly sense but !constant PHP_INT_MAX is really nicer.

@fabpot
Copy link
Member

fabpot commented Apr 29, 2016

I'm against adding something that does not follow the YAML specification.

@dunglas
Copy link
Member

dunglas commented Apr 29, 2016

If I understand correctly the spec, both proposals are valid: http://www.yaml.org/spec/1.2/spec.html#id2782728

@@ -22,6 +22,7 @@
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Yaml\Yaml;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please move it one line up in the yaml group?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure about this? The "good way" would be to move up the Expression line but as a CS fix it shouldn't be done in master, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's group yaml lines now that we can (but we don't move existing lines to reduce merge conflicts)

@HeahDude
Copy link
Contributor Author

Comments addressed. Waiting for tests to be green, needs review, thanks!

@fabpot
Copy link
Member

fabpot commented Jun 15, 2016

👍

@@ -366,7 +367,7 @@ protected function loadFile($file)
}

try {
$configuration = $this->yamlParser->parse(file_get_contents($file));
$configuration = $this->yamlParser->parse(file_get_contents($file), Yaml::PARSE_CONSTANT);
} catch (ParseException $e) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Symfony\Component\Yaml\Exception\RuntimeException might not be caught here, @xabbuh any ideas on how we should handle it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicolas-grekas
Copy link
Member

Status: needs work

@HeahDude
Copy link
Contributor Author

HeahDude commented Jun 17, 2016

Updated.

@HeahDude
Copy link
Contributor Author

Status: Needs Review

@fabpot
Copy link
Member

fabpot commented Jun 21, 2016

👍 (failures not related)

throw new ParseException(sprintf('The constant "%s" is not defined.', $const));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException(sprintf('The string "%s" could not be parsed as constant. Have you forgotten to pass "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] pass the [...]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] be parsed as a constant.

@fabpot
Copy link
Member

fabpot commented Jun 22, 2016

@HeahDude Can you take @xabbuh comments into account?

@HeahDude HeahDude force-pushed the feature/yaml-php-const branch 2 times, most recently from 4f861c0 to 17ec26e Compare June 23, 2016 13:44
@fabpot
Copy link
Member

fabpot commented Jun 23, 2016

Thank you @HeahDude.

@fabpot fabpot merged commit 17ec26e into symfony:master Jun 23, 2016
fabpot added a commit that referenced this pull request Jun 23, 2016
This PR was merged into the 3.2-dev branch.

Discussion
----------

[Yaml] Added support for parsing PHP constants

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | ~
| License       | MIT
| Doc PR        | TODO

Commits
-------

17ec26e [DI] added support for PHP constants in yaml configuration files
02d1dea [Yaml] added support for parsing PHP constants
@HeahDude HeahDude deleted the feature/yaml-php-const branch June 23, 2016 14:07
@fabpot fabpot mentioned this pull request Oct 27, 2016
@teohhanhui
Copy link
Contributor

teohhanhui commented Jun 2, 2017

It's unfortunate that we did not consider it important to adhere to the YAML spec: http://www.yaml.org/spec/1.2/spec.html#tag/local/

EDIT: See #22913 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.