Am 08.02.2015 03:39 schrieb "Rasmus Lerdorf" rasmus@lerdorf.com:
Basically declare() does not respect function scope, but it doesn't let
you know that. There is a reason we haven't used declare() for anything
real.
That is absolutely awful. But it's a fault with declare. Can't that be
fixed once and for all by fixing declare parsing - when used that way
inside a function, make its scope end with the end of the function, as we
would all have expected it to be, and as it would be when used in the
declare-with-a-block-form?
I chose a different subject, as it's an issue separate from the strict
typing thing itself.
declare is, to me, a very useful construct. Somebody recently wrote that it
is "just" a localized version of ini settings. That's right - it's the way
language (interpretation) settings SHOULD BE: give the power LOCALLY to the
coder, with effects LOCALLY in the file and/or scope where it is used, and
for the selective purpose given in the declare conditions. This is the ONLY
sane way to make such switches. It does not magically make code fail when
nonlocal stuff (ini settings) is changed, and it is more-locally
reversible, in its block form, when needed.
It is all about giving power to the calling code, which is a good thing
with the potential to resolve several of the long standing discussions on
this list. I applaud Andrea for having seen this, and followed through with
it, regarding strict type checks. Other issues that may be solved in a
similar way, using declare as a local behaviour switch, are:
-
scoped, stacked modifications to error handling:
- overriding, for a while, the current global error handler
- autoconversion of errors to exceptions
- autoconversion of exceptions to errors
- suppression of error output (without affecting handling itself)
-
assertions/pre/postconditions, as recently discussed in the DbC thread
-
an in-PHP alternative to #ifdeffery, for leaving out code fragments based
on the presence or values of already defined constants. Something I'd love
to have.... This would provide a nicer way for BC and FC handling code, and
if declare could be made to pretty much ignore the detailled content of its
block (except for curly brace matching), would even work out for reserved
keyword issues. -
a generic way to change ini settings with automatic resetting at the end
of the declare block/scope. -
a hook for extensions to introduce new declare conditions, with the
extension getting, in AST form, the condition value, and a way to
selectively operate on the declare block or rest-of-file AST.
Apart from fixing the declare function scoping thing, a second modification
might be needed in general, to go forward and backward with it afterwards:
ignore unknown declare conditions, with a safe semantic meaning of
leaving out the block (or rest of file, in the nonblock form, a la
__halt_compiler!) altogether.
So there you have it, my vision of what poor mistreated declare could be.
Do with it what you like.
But I had to write it down...
best regards
Patrick
Am 08.02.2015 03:39 schrieb "Rasmus Lerdorf" rasmus@lerdorf.com:
Basically declare() does not respect function scope, but it doesn't let
you know that. There is a reason we haven't used declare() for anything
real.
That is absolutely awful. But it's a fault with declare. Can't that be
fixed once and for all by fixing declare parsing - when used that way
inside a function, make its scope end with the end of the function, as we
would all have expected it to be, and as it would be when used in the
declare-with-a-block-form?I chose a different subject, as it's an issue separate from the strict
typing thing itself.declare is, to me, a very useful construct. Somebody recently wrote that it
is "just" a localized version of ini settings. That's right - it's the way
language (interpretation) settings SHOULD BE: give the power LOCALLY to the
coder, with effects LOCALLY in the file and/or scope where it is used, and
for the selective purpose given in the declare conditions. This is the ONLY
sane way to make such switches. It does not magically make code fail when
nonlocal stuff (ini settings) is changed, and it is more-locally
reversible, in its block form, when needed.It is all about giving power to the calling code, which is a good thing
with the potential to resolve several of the long standing discussions on
this list. I applaud Andrea for having seen this, and followed through with
it, regarding strict type checks. Other issues that may be solved in a
similar way, using declare as a local behaviour switch, are:
scoped, stacked modifications to error handling:
- overriding, for a while, the current global error handler
- autoconversion of errors to exceptions
- autoconversion of exceptions to errors
- suppression of error output (without affecting handling itself)
assertions/pre/postconditions, as recently discussed in the DbC thread
an in-PHP alternative to #ifdeffery, for leaving out code fragments based
on the presence or values of already defined constants. Something I'd love
to have.... This would provide a nicer way for BC and FC handling code, and
if declare could be made to pretty much ignore the detailled content of its
block (except for curly brace matching), would even work out for reserved
keyword issues.a generic way to change ini settings with automatic resetting at the end
of the declare block/scope.a hook for extensions to introduce new declare conditions, with the
extension getting, in AST form, the condition value, and a way to
selectively operate on the declare block or rest-of-file AST.So there you have it, my vision of what poor mistreated declare could be.
Do with it what you like.
But I had to write it down...
I agree with pretty much everything in this post.
While it is messy to have a language with too many runtime behaviours,
it's much more useful to have them explicitly and lexically scoped than
to have them either global or dnyamically toggled at runtime, which are
the options ini settings have now. The problem, I guess, is in how you
implement it - does the declare directive have to cause the compiler to
emit different opcodes for this file, or does it require extra code to
run on every entry and exit.
For instance, this would be really useful to wrap around legacy code
that is being phased out rather than improved:
declare(error_handling=E_WARNING|E_ERROR) {
function foo() { ... }
function bar() { ... }
}
The only way I can think to implement that is to add opcodes to the
beginning and end of each function to push and pop the setting each time
the code is called - the low-level equivalent of "$old_eh =
error_reporting(E_WARNING|E_ERROR); ... error_reporting($old_eh);" I
don't know how much overhead that would incur in practice; presumably
unlike @ it wouldn't defeat optimisations, since the start of a function
definition is always a boundary to that kind of thing anyway?
Apart from fixing the declare function scoping thing, a second modification
might be needed in general, to go forward and backward with it afterwards:
ignore unknown declare conditions, with a safe semantic meaning of
leaving out the block (or rest of file, in the nonblock form, a la
__halt_compiler!) altogether.
I think it's a shame that declare() itself wasn't always implemented
with forwards-compatibility in mind. In some cases (probably including
strict types) the declaration itself could be completely ignored, rather
than causing the file to be parsed as empty (which is probably no more
useful than it emitting a parse error). I wonder if it's feasible to
write extensions for old versions of PHP which add new declare()
directives?
Regards,
--
Rowan Collins
[IMSoP]