Re: Wired constant expression syntax and bug

From: Date: Tue, 01 Jul 2014 11:25:12 +0000
Subject: Re: Wired constant expression syntax and bug
References: 1 2 3 4  Groups: php.internals 
Request: Send a blank email to internals+get-75161@lists.php.net to get a copy of this message
Am 1.7.2014 um 09:12 schrieb Nikita Popov <nikita.ppv@gmail.com>: > > > > > > > > > class FooBar { > > > const bar = ["bar" => 3]["bar"]; > > > } > > > > > > It wasn't a part of RFC, it wasn't covered by tests, and it actually > > > doesn't make a lot of sense. May be it's better to remove it? > > > > I disagree, it makes perfect sense: > > > > class FooBar { > > const FOO = 3; > > const BAR = [ > > 3 => ‘qux’, > > 4 => ‘bang’, > > 7 => ‘theta’, > > 9 => ‘epsilon’ > > ][FOO]; > > } > > > > ?: and ? only work when there are just two possibilities. > > > > ?: may work with brackets, but I have to admit that it's less readable. > > class Foo { > const X = 2; > const Y = (Foo::X == 0 ? 1 : > (Foo::X == 1 ? 2 : > (Foo::X == 2 ? 3 : > (Foo::X == 3 ? 4 : > 5)))); > } > > The situation is really inconsistent because we allow expressions on > constant arrays but at the same time prohibit array usage. > > As we support the [..., ...][...] syntax in normal PHP code as well, I think it's > reasonable to allow it here as well. Of course it isn't very practically useful, but there > doesn't seem much point to explicitly disallowing it here. That's exactly my point. > Look into the following scripts: > > > <?php > class Foo { > const BAR = [ > 3 => ‘qux’, > 4 => ‘bang’, > 7 => ‘theta’, > 9 => ‘epsilon’ > ][1]; > } > var_dump(Foo::BAR); // works - prints 'bang' > ?> > > <?php > class Foo { > const BAR = [ > 3 => ‘qux’, > 4 => ‘bang’, > 7 => ‘theta’, > 9 => ‘epsilon’ > ]; > } > var_dump(Foo::BAR); // doesn't work - Fatal error: Arrays are not allowed > in constants at run-time > ?> > > <?php > class Foo { > const BAR = [ > 3 => ‘qux’, > 4 => ‘bang’, > 7 => ‘theta’, > 9 => ‘epsilon’ > ]; > } > // This works again! We may declare array class constants if we don't use > them? > ?> > > Where is the logic? > > The reason here is probably that we cannot detect whether something will be an array or not > until runtime constant updating. E.g. const BAR = FOO ? 1 : [1] or similar. However we might want to > detect the case where an array is the root of the AST, as that is invalid for sure and the most > common case. Not sure if we should check that. That would be adding a new arbitrary restriction. Now the following works: class Foo { const BAR = [ 3 => ‘qux’, 4 => ‘bang’, 7 => ‘theta’, 9 => ‘epsilon’ ]; const BAZ = FOO[4]; } var_dump(Foo::BAZ); > Another small issue with the constant expressions I noticed is that our recursion detection > doesn't properly work for constant ASTs. For example: > > <?php > class A { > const FOO = [self::BAR]; > const BAR = [self::FOO]; > } > var_dump(A::FOO); > > This will result in a stack overflow instead of a fatal error about self-referencing constants. > > Nikita I think that this is caused by some bugfix for opcache. http://lxr.php.net/xref/PHP_5_6/Zend/zend_ast.c#255 That zval_copy_ctor call duplicates the AST to save it for opcache so that opcache can store it later. But as that is called before the zend_ast_evaluate, the effects of MARK_CONSTANT_VISITED() won't affect the contents of the ast (and the zval with the constant) copied before… @Dmitry: Removing this call (and the dtoring in the ast destructor) will break opcache and fix this bug. How to fix both now? I don't immediately see a good fix here? Bob

« previous php.internals (#75161) next »