php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68485 late namespace resolution with cross-namespace inheritance missing
Submitted: 2014-11-23 21:50 UTC Modified: 2014-11-24 23:42 UTC
From: llmll at gmx dot de Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: 5.5.19 OS: any
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: llmll at gmx dot de
New email:
PHP Version: OS:

Further comment on this bug is unnecessary.

 

 [2014-11-23 21:50 UTC] llmll at gmx dot de
Description:
------------
Since PHP 5.3 we have late static binding to get a static variable from the actually instantiated class type instead of the declared type. This is an important feature, but it does not take into account a change in namespace. If the inheriting class lives in another namespace the wrong value is taken.

If inside a namespace a class uses a peer class by its relative name, and later both classes are derived in another namespace, all accesses go to the original namespace where the class was declared in the first place.

Neccessary would be a late (runtime) namespace resolution for class names, the same was it works for static::

Test script:
---------------
<?php

namespace Alpha;

class Base {
	public static function Write() {
		echo Helper::$Value;
	}
}

class Helper {
	public static $Value = "ALPHA";
}


namespace Beta;

class Base extends \Alpha\Base {

}	

class Helper extends \Alpha\Helper {
	public static $Value = 'BETA';
}	

\Beta\Base::Write();

?>

Expected result:
----------------
As the exmple calls \Beta\Base::Write() in \Beta namespace one would expect the output to be "BETA". The original static property is overwritten in Beta-namespace

The calls Helper::$Value should be call-context-sensitive. If called in namespace \Alpha it shoult print "ALPHA" if called from a \Beta class, "BETA".

Actual result:
--------------
prints "ALPHA"

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-11-23 22:35 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2014-11-23 22:35 UTC] requinix@php.net
LSB happens with the static keyword, not class names. Classes always resolve according to the namespace of the code being executed (or by use statements), not some kind of contextual namespace dependent on where the code is being executed.

echo static::$Value;

Don't forget that trying to access an undefined static property will fatal.
 [2014-11-23 23:03 UTC] llmll at gmx dot de
Sorry to say, but you did not understand the example provided. Please go through it again and find that it has nothing to do with late static binding.

Your suggestion is invalid. A static::$Value is not defined, as we want the $Value property of a different class: \Alpha\Helper. So we access it as Helper::$Value.

And here comes the problem. When later both classes are inherited / copied to \Beta namespace, the Helper::$Value readout still accesses \Alpha\Helper::$Values, but it should be using \Beta\Helper::$Value.
 [2014-11-23 23:43 UTC] requinix@php.net
That may be but it's still not a bug. There is no such feature like what you're describing; the closest is LSB which is why I brought it up.

Your options include
a) Beta\Base redefining Write() to use the Helper class that it wants to use.
b) (Ab)using get_called_class() to extract the called namespace, test that the corresponding Helper class exists, and use its $Value.
c) Dependency injection, which sounds like the best solution to whatever you're trying to do.
 [2014-11-23 23:59 UTC] llmll at gmx dot de
The example shows a clear breach in namespace/inheritance logic - this qualifies as bug.

As you explain a mere c&p of the method to the new class would resolve the issue. I remeber reading nearly the same tips here, when LSB wasn't there and people claimed __CLASS__ was sufficient for everything and for everything else just c&p. I personally stay away from hackish tricks, the important namespace functionality should be consistent. So my suggestion is focusing on the problem not the alternatives.
 [2014-11-24 00:51 UTC] requinix@php.net
There is no inheritance in the first place. "Helper::$Value" does not work as a relative path but is merely shorthand for writing "\Alpha\Helper::$Value", and was resolved as such at compile-time.

The feature you're trying to report a bug for *does not exist*.
 [2014-11-24 07:29 UTC] llmll at gmx dot de
Sorry, but you are wrong again. Please double check your own PHP documentation, where it says:

"Inside namespace (say A\B), calls to **unqualified** or qualified class names (not fully qualified class names) are resolved at **run-time**. ".

This describes exactly what I am expecting.
 [2014-11-24 08:32 UTC] requinix@php.net
Hmm. Compile-time for imports and HHVM seems to do it at compile-time regardless <http://3v4l.org/Ec0jL/bytecode#tabs>. I guess I assumed it was compile-time for everything.

Regardless, the class name still isn't resolved that way. Did you see the next line? "It looks for a class from the current namespace: A\B\C."
- It had just said that A\B was where the "call" was
- There is no mention of any other code anywhere else - including code calling the code being executed

Now, can we call this resolved? I'm sorry about the mix-up but it simply does not work the way you thought it did. And frankly I'm glad it doesn't because such a scheme would be very confusing and awkward.
 [2014-11-24 13:06 UTC] llmll at gmx dot de
As written before this is a breach. The documentation is clear and consistent: Resolution is done at runtime, and -regarding your quote- respects the current namespace context, so in my example at runtime the instance is in \Beta namespace and this namespace and it's class should be used. That is the only logical and deterministic way to interpret the call to Helper::$Value. Other languages follow this priciple.

So IMHO this remains a serious flaw, because PHP does not behave like expected and documented. You may call it a missing feature, though, that does not change the facts I pointed out.
 [2014-11-24 23:42 UTC] requinix@php.net
-Block user comment: No +Block user comment: Yes
 [2014-11-24 23:42 UTC] requinix@php.net
https://gist.github.com/requinix/c3a576a5a8953d26da02

I've said all I can on this and there is no point trying to continue this debate. If I still haven't hit upon the right combination of words and explained to you why you're mistaken and why there is no bug then I doubt I ever could and you need to find somebody else willing to try.
http://php.net/support.php
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Apr 29 19:01:30 2024 UTC