[RFC] Add PHP_ENGINE Constant

php.internals

Davey

10 years ago
Hi all, I want to bring forward a very simple RFC to help solve an issue I had this week of writing unit tests that take into account differing behaviors in PHP and HHVM. It's actually very difficult to be able to reliably determine that you are running the _real_ PHP runtime and not something mimicking it. And while it's easy to detect HHVM, for example, there's no way to detect not-PHP, or to reliably detect any other number of runtimes. Therefore, I'd like to propose we add a simple string constant, PHP_ENGINE that contains the runtime name, be that 'php', 'hhvm', 'hippyvm', or something else. Additionally, because you are likely to want to also know the version of said engine, and don't want to mess around with checking the engine appropriate constants based on the value of PHP_ENGINE (e.g. HHVM_VERSION), I'm proposing we also add PHP_ENGINE(_*)_VERSION(_ID), which means you can then check all the version constants for whatever VM you happen to be on easily. This also means that we can agree on the current behavior of using PHP_VERSION (and PHP(_*)_VERSION(_ID) to allow the running on legacy code that depends on it, on newer runtimes. RFC, with patches, is here: https://wiki.php.net/rfc/php_engine_constant Thanks, - Davey

Dan Ackroyd

10 years ago
On 3 February 2016 at 09:03, Davey Shafik <davey@php.net> wrote:
> Hi all, > > It's actually very difficult to be able to reliably determine that you are > running the _real_ PHP runtime and not something mimicking it.
The underlying problem seems to be caused by HHVM deliberately 'faking' the results of calls to zend_version() and the existing constants. What is there to stop any other PHP implementations from returning 'fake' data for that function or these new constants? And just to play devils advocate, why isn't this a problem that should be solved in those other versions of PHP? They're the ones re-using version strings and so causing confusion. I can see how this could be useful....I just can't see how this would be a permanent solution to the problem. As someone else said, this sounds like the old detecting browsers via "user agent headers" for browser detection. That became a complete nightmare as browsers kept imitating each other, and so the rules about strings became less and less useful. Perhaps it might be helpful to justify the RFC, if you can give some more context as to why code needs to know about what VM it is running on? cheers Dan

Andreas Heigl

10 years ago
Am 03.02.16 um 17:54 schrieb Dan Ackroyd:
> On 3 February 2016 at 09:03, Davey Shafik <davey@php.net> wrote: >> Hi all, >> >> It's actually very difficult to be able to reliably determine that you are >> running the _real_ PHP runtime and not something mimicking it. > > The underlying problem seems to be caused by HHVM deliberately > 'faking' the results of calls to zend_version() and the existing > constants. What is there to stop any other PHP implementations from > returning 'fake' data for that function or these new constants? > > And just to play devils advocate, why isn't this a problem that should > be solved in those other versions of PHP? They're the ones re-using > version strings and so causing confusion. > > I can see how this could be useful....I just can't see how this would > be a permanent solution to the problem. As someone else said, this > sounds like the old detecting browsers via "user agent headers" for > browser detection. That became a complete nightmare as browsers kept > imitating each other, and so the rules about strings became less and > less useful. > > Perhaps it might be helpful to justify the RFC, if you can give some > more context as to why code needs to know about what VM it is running > on?
Especially when running tests on f.i. Travis-CI you can set an environment variable to describe what environment you are supposed to be in. In all other cases feature-detection (function_exists/extension_loaded f.i.) should work fine to determine whether the used engine is able to run a certain function. And in the end the goal would be to not adapt the code to different runtine-engines but to adapt the runtime engines to run the code in the same manner. That's what the language-specification is there for. My 2 Cent Cheers Andreas
> > cheers > Dan >
-- ,,, (o o) +---------------------------------------------------------ooO-(_)-Ooo-+ | Andreas Heigl | | mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" | | http://andreas.heigl.org http://hei.gl/wiFKy7 | +---------------------------------------------------------------------+ | http://hei.gl/root-ca | +---------------------------------------------------------------------+

Matt Prelude

10 years ago
Hi, On 03/02/16 16:54, Dan Ackroyd wrote:
> On 3 February 2016 at 09:03, Davey Shafik <davey@php.net> wrote: >> Hi all, >> >> It's actually very difficult to be able to reliably determine that you are >> running the _real_ PHP runtime and not something mimicking it. > The underlying problem seems to be caused by HHVM deliberately > 'faking' the results of calls to zend_version() and the existing > constants. What is there to stop any other PHP implementations from > returning 'fake' data for that function or these new constants? > > And just to play devils advocate, why isn't this a problem that should > be solved in those other versions of PHP? They're the ones re-using > version strings and so causing confusion. > > I can see how this could be useful....I just can't see how this would > be a permanent solution to the problem. As someone else said, this > sounds like the old detecting browsers via "user agent headers" for > browser detection. That became a complete nightmare as browsers kept > imitating each other, and so the rules about strings became less and > less useful. > > Perhaps it might be helpful to justify the RFC, if you can give some > more context as to why code needs to know about what VM it is running > on? > > cheers > Dan >
I think Dan raises some interesting points, although I think zend_version() is often used for feature detection so they try to put a zend version in there to be helpful i.e. HHVM x.y.z === PHP a.b (feature-wise). I can see how this could be useful. Would get my +1 if I had a vote.

Kinn Julião

10 years ago
On Wed, Feb 3, 2016 at 12:07 PM, Matt Prelude <me@mprelu.de> wrote:
> Hi, > > On 03/02/16 16:54, Dan Ackroyd wrote: > >> On 3 February 2016 at 09:03, Davey Shafik <davey@php.net> wrote: >> >>> Hi all, >>> >>> It's actually very difficult to be able to reliably determine that you >>> are >>> running the _real_ PHP runtime and not something mimicking it. >>> >> The underlying problem seems to be caused by HHVM deliberately >> 'faking' the results of calls to zend_version() and the existing >> constants. What is there to stop any other PHP implementations from >> returning 'fake' data for that function or these new constants? >> >> And just to play devils advocate, why isn't this a problem that should >> be solved in those other versions of PHP? They're the ones re-using >> version strings and so causing confusion. >> >> I can see how this could be useful....I just can't see how this would >> be a permanent solution to the problem. As someone else said, this >> sounds like the old detecting browsers via "user agent headers" for >> browser detection. That became a complete nightmare as browsers kept >> imitating each other, and so the rules about strings became less and >> less useful. >> >> Perhaps it might be helpful to justify the RFC, if you can give some >> more context as to why code needs to know about what VM it is running >> on? >> >> cheers >> Dan >> >> I think Dan raises some interesting points, although I think > zend_version() is often used for feature detection so they try to put a > zend version in there to be helpful i.e. HHVM x.y.z === PHP a.b > (feature-wise). > > I can see how this could be useful. Would get my +1 if I had a vote. > > > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
I agree with Andreas when: And in the end the goal would be to not adapt the code to different
> runtine-engines but to adapt the runtime engines to run the code in the > same manner. That's what the language-specification is there for.
If the motivation is:
> I want to bring forward a very simple RFC to help solve an issue I had this > week of writing unit tests that take into account differing behaviors in > PHP and HHVM.
I suggest the following http://hhvm.com/blog/2393/hhvm-2-3-0-and-travis-ci and instead of introducing one more constant, you could easily use *if (defined('HHVM_VERSION')) {}*
-- *--* *Kinn Coelho Julião* *Toronto - ON/Canada*

Sara Golemon

10 years ago
> I think Dan raises some interesting points, although I think zend_version() > is often used for feature detection so they try to put a zend version in > there to be helpful i.e. HHVM x.y.z === PHP a.b (feature-wise). >
That's exactly why PHP_VERSION is faked in HHVM. Because that's how users use it. Essentially, we're treating PHP_VERSION as "PHP language specification version X.Y" So for example, hhvm 3.12.0 conforms to phplang-spec 7.0.0 so it defines HHVM_VERSION to tell what it is, while PHP_VERSION exists for all those scripts that were written under the assumption that there's only one PHP runtime. I would actually suggest that if something like this RFC goes through, we formally define PHP_VERSION in exactly that way. As a language specification conformance advertisement. PHP_ENGINE_VERSION would be the build ID for the actual runtime implementation. In the case of the reference implementation, these numbers would be identical, so there would be no effective change. In the case of other implementations, they'd differ. For example on HHVM you'd have: PHP_VERSION=7.0.0, PHP_ENGINE=hhvm, PHP_ENGINE_VERSION=3.12.0 All that said, I'm not convinced we *need* explicitly enumerated constants like PHP_ENGINE, but for that 0.1% of scripts that care who they're running under, it would certainly unify that detection in a useful way. To the question of "are we just replicating browser detection and all its problems?", I'd offer that perhaps the solution lies not in more constants, but in Reflection. For example: class ReflectionLanguage { public function isSupported($feature): bool; public function variableSyntaxConformance(): string; public function strictTypehints(): bool; } Some of these would be compiler constant-ish, others might be per-file (like strictTypeHints()). ^^ The above is a half-baked idea, please alter/destroy it at will. -Sara

Davey

10 years ago
On Wednesday, February 3, 2016, Sara Golemon <pollita@php.net> wrote:
> > I think Dan raises some interesting points, although I think > zend_version() > > is often used for feature detection so they try to put a zend version in > > there to be helpful i.e. HHVM x.y.z === PHP a.b (feature-wise). > > > That's exactly why PHP_VERSION is faked in HHVM. Because that's how > users use it. Essentially, we're treating PHP_VERSION as "PHP > language specification version X.Y" So for example, hhvm 3.12.0 > conforms to phplang-spec 7.0.0 so it defines HHVM_VERSION to tell what > it is, while PHP_VERSION exists for all those scripts that were > written under the assumption that there's only one PHP runtime. > > I would actually suggest that if something like this RFC goes through, > we formally define PHP_VERSION in exactly that way. As a language > specification conformance advertisement. PHP_ENGINE_VERSION would be > the build ID for the actual runtime implementation. In the case of > the reference implementation, these numbers would be identical, so > there would be no effective change. In the case of other > implementations, they'd differ. For example on HHVM you'd have: > PHP_VERSION=7.0.0, PHP_ENGINE=hhvm, PHP_ENGINE_VERSION=3.12.0 > > All that said, I'm not convinced we *need* explicitly enumerated > constants like PHP_ENGINE, but for that 0.1% of scripts that care who > they're running under, it would certainly unify that detection in a > useful way. > > To the question of "are we just replicating browser detection and all > its problems?", I'd offer that perhaps the solution lies not in more > constants, but in Reflection. For example: > > class ReflectionLanguage { > public function isSupported($feature): bool; > public function variableSyntaxConformance(): string; > public function strictTypehints(): bool; > } > > Some of these would be compiler constant-ish, others might be per-file > (like strictTypeHints()). > > ^^ The above is a half-baked idea, please alter/destroy it at will. >
Unfortunately Sara, the types of things you generally have to work around are minor things, like differences in DOM, or the inability to json_encode DateTimeImmuteable I do however like the idea of feature detection - I wonder if perhaps we could do something where it's done at compile time and therefore minimally impacts runtime?

Fred Emmott

10 years ago
> On Feb 3, 2016, at 2:00 PM, Davey Shafik <davey@php.net> wrote: > > On Wednesday, February 3, 2016, Sara Golemon <pollita@php.net <mailto:pollita@php.net>> wrote: > > Unfortunately Sara, the types of things you generally have to work around > are minor things, like differences in DOM, or the inability to json_encode > DateTimeImmuteable
It seems like the main thing this RFC would change is that you could easily do “if ($engine !== ‘php’)” - but for almost all the examples I can think of, and yours, what’s actually needed is if "($engine === ‘specific_engine_that_needs_a_workaround’)”, so I don’t see a benefit over using HHVM_VERSION or similar. The one exception I can think of is if someone’s reimplementing phpinfo() or similar. Regards, - Fred

Davey

10 years ago
Currently, HippyVM doesn't even _have_ a version constant. Because it's trying to pretend to be PHP. Having a "YOU MUST FILL THESE CONSTANTS WITH YOUR OWN RUNTIMES DATA" in the spec is intended to help that situation. Right now, there's no way to tell what version of HippyVM you're running on, and to even check that you're using Hippy you need to check for E_HIPPY_WARN. We have a chance to standardize, and "mandate" that the information is exposed explicitly, and done so consistently. On Wed, Feb 3, 2016 at 5:14 PM, Fred Emmott <fred@fredemmott.co.uk> wrote:

Fred Emmott

10 years ago
Fair enough - though I’m not convinced that it would be effective: if successful, it would allow people to do 90’s-browser-sniffing-style if ($engine !== ‘my favorite’) throw Exception(’sorry, not supported yet’);, so it seems fairly likely that implementations would end up lying about it (and yes, deviating from the spec) in a few years anyway. As a side note, AFAIK HippyVM isn’t being actively developed (https://twitter.com/HippyVM/status/634347845957627904 <https://twitter.com/HippyVM/status/634347845957627904>)

Rowan Collins

10 years ago
Fred Emmott wrote on 03/02/2016 22:14:
>> On Feb 3, 2016, at 2:00 PM, Davey Shafik <davey@php.net> wrote: >> >> On Wednesday, February 3, 2016, Sara Golemon <pollita@php.net <mailto:pollita@php.net>> wrote: >> >> Unfortunately Sara, the types of things you generally have to work around >> are minor things, like differences in DOM, or the inability to json_encode >> DateTimeImmuteable > > It seems like the main thing this RFC would change is that you could easily do “if ($engine !== ‘php’)” - but for almost all the examples I can think of, and yours, what’s actually needed is if "($engine === ‘specific_engine_that_needs_a_workaround’)”, so I don’t see a benefit over using HHVM_VERSION or similar. > > The one exception I can think of is if someone’s reimplementing phpinfo() or similar.
Maybe what's actually needed is not something in the PHP spec itself, but a PHP equivalent of modernizr (https://modernizr.com/) - a library with a set of feature detections which bypass the whole question of "real PHP" or needing to know the exact quirks of every implementation. It would also be much easier to maintain and extend if it existed outside of any implementation, rather than needing every implementation to keep up with a growing list of requirements [first feature to detect: is the feature detection API present? ;)] It could perhaps take the form of a set of unit tests which you run as part of a build process that then writes out a profile of the current environment. This would allow you to detect even things which cause fatal errors on some implementations, by triggering the error in a sub-process, and would be more efficient than probing them at runtime. Regards,
-- Rowan Collins [IMSoP]

Pierre Joye

10 years ago
On Thu, Feb 4, 2016 at 2:00 AM, Davey Shafik <davey@php.net> wrote:
> On Wednesday, February 3, 2016, Sara Golemon <pollita@php.net> wrote: > >> > I think Dan raises some interesting points, although I think >> zend_version() >> > is often used for feature detection so they try to put a zend version in >> > there to be helpful i.e. HHVM x.y.z === PHP a.b (feature-wise). >> > >> That's exactly why PHP_VERSION is faked in HHVM. Because that's how >> users use it. Essentially, we're treating PHP_VERSION as "PHP >> language specification version X.Y" So for example, hhvm 3.12.0 >> conforms to phplang-spec 7.0.0 so it defines HHVM_VERSION to tell what >> it is, while PHP_VERSION exists for all those scripts that were >> written under the assumption that there's only one PHP runtime. >> >> I would actually suggest that if something like this RFC goes through, >> we formally define PHP_VERSION in exactly that way. As a language >> specification conformance advertisement. PHP_ENGINE_VERSION would be >> the build ID for the actual runtime implementation. In the case of >> the reference implementation, these numbers would be identical, so >> there would be no effective change. In the case of other >> implementations, they'd differ. For example on HHVM you'd have: >> PHP_VERSION=7.0.0, PHP_ENGINE=hhvm, PHP_ENGINE_VERSION=3.12.0 >> >> All that said, I'm not convinced we *need* explicitly enumerated >> constants like PHP_ENGINE, but for that 0.1% of scripts that care who >> they're running under, it would certainly unify that detection in a >> useful way. >> >> To the question of "are we just replicating browser detection and all >> its problems?", I'd offer that perhaps the solution lies not in more >> constants, but in Reflection. For example: >> >> class ReflectionLanguage { >> public function isSupported($feature): bool; >> public function variableSyntaxConformance(): string; >> public function strictTypehints(): bool; >> } >> >> Some of these would be compiler constant-ish, others might be per-file >> (like strictTypeHints()). >> >> ^^ The above is a half-baked idea, please alter/destroy it at will. >>
I am also really not convinced we need a PHP_ENGINE_* set of constants. It defeats the purpose of these constants. Each non php.net implementation could (should?) have a <implementation> and <implementation>_<version> constants, for instance, HHVM and HHVM_VERSIONS_* constants. These constants can then be used to do the required work-around for bugs or to use implementation specific features.
> Unfortunately Sara, the types of things you generally have to work around > are minor things, like differences in DOM, or the inability to json_encode > DateTimeImmuteable > > I do however like the idea of feature detection - I wonder if perhaps we > could do something where it's done at compile time and therefore minimally > impacts runtime?
This could be what you actually need. A #ifdef equivalent for PHP. I remember a discussion about adding these features to the core to allow to enable/disable portions of a script at the parsing/compilation level. Doing so allows mixing codes being valid for various implementations inside a same file. It is especially important for features using syntax not compatible with a php.net's PHP specification (for instance). I am not very keen about that either as I prefer to use separate files. However it seems to be where we could move forward for these kind of needs? parser/compilation time constants or expression (like HAVE_FOO in C for example but only defined by the respective engine and maybe extensions) as well as at runtime (as normal PHP constants). Just a thought :) Cheers,
-- Pierre @pierrejoye | http://www.libgd.org

Davey

10 years ago
As an aside, having this kind of #ifdef type stuff also allows us to write forward compatible scripts without worrying about invalid syntax breaking older versions. On Fri, Feb 5, 2016 at 11:20 AM, Pierre Joye <pierre.php@gmail.com> wrote:

Sara Golemon

10 years ago
On Fri, Feb 5, 2016 at 8:20 AM, Pierre Joye <pierre.php@gmail.com> wrote:
>> I do however like the idea of feature detection - I wonder if perhaps we >> could do something where it's done at compile time and therefore minimally >> impacts runtime? > > This could be what you actually need. A #ifdef equivalent for PHP. I > remember a discussion about adding these features to the core to allow > to enable/disable portions of a script at the parsing/compilation > level. Doing so allows mixing codes being valid for various > implementations inside a same file. It is especially important for > features using syntax not compatible with a php.net's PHP > specification (for instance). >
This usually results in some half-hearted attempts followed by "just use gcc's preprocessor for that". :) -Sara

Pierre Joye

10 years ago
On Feb 6, 2016 3:02 AM, "Sara Golemon" <pollita@php.net> wrote:
> > On Fri, Feb 5, 2016 at 8:20 AM, Pierre Joye <pierre.php@gmail.com> wrote: > >> I do however like the idea of feature detection - I wonder if perhaps
we
> >> could do something where it's done at compile time and therefore
minimally
> >> impacts runtime? > > > > This could be what you actually need. A #ifdef equivalent for PHP. I > > remember a discussion about adding these features to the core to allow > > to enable/disable portions of a script at the parsing/compilation > > level. Doing so allows mixing codes being valid for various > > implementations inside a same file. It is especially important for > > features using syntax not compatible with a php.net's PHP > > specification (for instance). > > > This usually results in some half-hearted attempts followed by "just > use gcc's preprocessor for that". :)
Yeah, preprocessor (gcc or other) sounds a bit awkward for php while I can understand why one or the other would like to have it. But still, having php code cluttered with #ifdef like codes is not very appealing :)

Stas Malyshev

10 years ago
Hi!
>> there to be helpful i.e. HHVM x.y.z === PHP a.b (feature-wise). >> > That's exactly why PHP_VERSION is faked in HHVM. Because that's how
And I think it is the right choice. PHP_VERSION essentially (also) means the version of the spec and of the implementation. And people do depend on it (despite better solution being to check for specific feature, but it's not always easy). I think having also HHVM_VERSION is enough to both detect HHVM and check for specific quirks if necessary. If you have another implementation, like Quercus, I'd expect something like QUERCUS_VERSION.
> I would actually suggest that if something like this RFC goes through, > we formally define PHP_VERSION in exactly that way. As a language > specification conformance advertisement. PHP_ENGINE_VERSION would be
Well, the thing there is that the spec does not define the library, and a lot of things do depend on library. So sometimes PHP_VERSION is also used to check for something we've added in minor version, and that won't be in the spec.
> class ReflectionLanguage { > public function isSupported($feature): bool; > public function variableSyntaxConformance(): string; > public function strictTypehints(): bool; > }
Yes, but would we add there something like "does foo_bar($baz, $zoo) support second parameter or not yet"? Or "is that annoying bug where bar_foo didn't support Unicode strings fixed or not?" People use version for that too.
-- Stas Malyshev smalyshev@gmail.com

Fred Emmott

10 years ago
> On Feb 3, 2016, at 4:03 AM, Davey Shafik <davey@php.net> wrote: > > Hi all, > > I want to bring forward a very simple RFC to help solve an issue I had this > week of writing unit tests that take into account differing behaviors in > PHP and HHVM. > > It's actually very difficult to be able to reliably determine that you are > running the _real_ PHP runtime and not something mimicking it.
Can you give more information on why “real PHP” and “not real PHP” would be useful to you? It sounds like you are working around HHVM bugs, so checking ‘am I on HHVM?’ is the correct thing to do - ‘Am I on something that is not PHP?’ is not, as other engines may not have the same bugs. Regards, - Fred