php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76766 Unexpected behavior, when using namespaces in one file
Submitted: 2018-08-20 07:30 UTC Modified: 2018-08-21 21:50 UTC
From: dirk dot gerigk at atraveo dot com Assigned:
Status: Open Package: *Compile Issues
PHP Version: 7.2.9 OS: Linux
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2018-08-20 07:30 UTC] dirk dot gerigk at atraveo dot com
Description:
------------
I tried to merge some namespace classes into one file and found some strange behavior. 

Questions: 
 - What are i'm missing to understand here? Or is that unexpected behavior?
 - At witch time is what compiled and when is the global namespace executed?
 - What effect has the use of an interface at the compile time?
 - Why is the global namespace not executed as last?


However, the current behavior makes it impossible to merge classes into one file, but i thought that is possible because of namespaces. 

'Fatal Error: Class '?\?' not found' is generated on the non working tests.

Test script:
---------------
#THIS WORKS
namespace X { class A extends B{} class B {} } namespace { new X\A; }
#THIS NOT
namespace { new X\A; } namespace X { class A extends B {} class B {} }

#THIS WORKS
namespace X { interface T {} class B implements T {} class A extends B {} }
namespace { new X\A; }
#THIS NOT
namespace X { class B implements T {} class A extends B {} interface T {}  }
namespace { new X\A; }

#THIS WORKS NOT
namespace X { class A extends B {}  class B implements T {} interface T {}  }
#THIS ALSO WORKS NOT 
namespace X { interface T {} class A extends B {} class B implements T {} }
#BUT THIS WORKS 
namespace X { class B implements T {} class A extends B {} interface T {}  }

#WORKS 
namespace C { class A {} } 
namespace { new X\A; } 
namespace X { class A extends \C\A {} }
#WORKS NOT
namespace { new X\A; } 
namespace X { class A extends \C\A {} } 
namespace C { class A {} }
#WORKS AGAIN
namespace X { class A extends \C\A {} }
namespace { new X\A; }
namespace C { class A {} }


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-08-20 07:37 UTC] dirk dot gerigk at atraveo dot com
As not for the first tests, if no interface is used and nothing extends nothing, the order of the of declaration can be random. So this works also fine:

namespace { new X\A; }
namespace X { class A {} }

Make your one combinations to see the strange behavior.
 [2018-08-20 23:13 UTC] a at b dot c dot de
Your namespaces are not the problem:

#THIS WORKS NOT
class A extends B {}  class B implements T {} interface T {}
#THIS ALSO WORKS NOT 
interface T {} class A extends B {} class B implements T {}
#BUT THIS WORKS 
class B implements T {} class A extends B {} interface T {}

Or your last example:

new A;
class A {}


Classes must be declared before they are instantiated/subclassed.
http://www.php.net/language.oop5.inheritance

I'm actually surprised that
class B implements T {} class A extends B {} interface T {}
works.
 [2018-08-21 07:37 UTC] dirk dot gerigk at atraveo dot com
But 
 new A;
 class A {}
should not work, 
because of 'Classes must be declared before they are instantiated/subclassed'

And what is strange with namespaces that sometimes the behavior changes when interfaces are used, like
this works
 namespace { new X\A; }
 namespace X {  class B  {} class A extends B {} }
this not
 namespace { new X\A; }
 namespace X { interface T {} class B implements T {} class A extends B {} }

In both examples the declaration is in the wrong order, but only the use of an interface breaks the code here.

Whatever, i was only pointing to the strange behavior that makes it mostly impossible to merge complex namespaces in one file, when also a global namespace is present that instantiates objects. 

All examples here are simplified. 
How strange can it be when you are using classes that are extending and implementing from other namespaces. I came across it while i was merging code into one file. 

By the way i was just trying it for no real reason, just want to know if its possible.

But thank for your comment
 [2018-08-21 08:43 UTC] requinix@php.net
> Classes must be declared before they are instantiated/subclassed.
That's *mostly* true. More specifically, classes must be known to PHP before code tries to use them, however some class information is available after PHP initially parses a file and before it's done a more in-depth analysis.
Defining classes in just about anything that uses {}s will disrupt that. https://3v4l.org/ZAEq1

But categorizing a namespace{} as one of the "anything that uses {}s" doesn't quite explain the reported behaviors.
 [2018-08-21 21:50 UTC] cmb@php.net
> That's *mostly* true.

Indeed, there are some exceptions, but I would prefer to not
overcomplicate the documentation, and also to leave some breathing
room for future changes to the engine.  After all, if code regards
this simple rule, it should work in all circumstances (but see
below).  For instance, the first non-working example in the OP
would have to be rewritten according to this rule to:

  namespace { new X\A; } namespace X { class B {} class A extends B {} }

which would compile without errors[1].

> Classes must be declared before they are instantiated/subclassed.
> http://www.php.net/language.oop5.inheritance

Hmm, it seems the referenced man page does not say anything
regarding instantiation, but rather speaks about extending classes
and implementing interfaces, respectively.  The former would only
be relevant, if the class definition won't be resolved during
compile time[2].  This is, however, basically the same for
functions[3], so likely should be documented elsewhere (unless it
already is).  Not sure if the language specification[4] already
addresses this.

[1] <https://3v4l.org/UNvcS>
[2] e.g. <https://3v4l.org/Xi4qg>
[3] <https://3v4l.org/YSpRN>
[4] <https://github.com/php/php-langspec>
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Mon Aug 19 12:01:26 2019 UTC