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
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
Am 03.02.16 um 17:54 schrieb Dan Ackroyd:
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 tozend_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 |
+---------------------------------------------------------------------+
Hi,
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 tozend_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.
Hi,
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 tozend_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
DanI 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.
--
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
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
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 treatingPHP_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, whilePHP_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 definePHP_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.0All 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?
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
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.
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
DateTimeImmuteableIt 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
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)
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.
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
DateTimeImmuteableIt 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
Fred Emmott wrote on 03/02/2016 22:14:
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
DateTimeImmuteableIt 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]
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 treatingPHP_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, whilePHP_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 definePHP_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.0All 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
DateTimeImmuteableI 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
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.
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 treatingPHP_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, whilePHP_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 definePHP_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.0All 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
DateTimeImmuteableI 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
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
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 :)
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 definePHP_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
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