rfc:namespaces

Request for Comments: Namespace Issues

Introduction

The purpose of this RFC is to document issues regarding the current namespace implementation (and where appropriate and available, to link to available patches), whether percieved or otherwise. Additionally it aims to offer a reference to mailing list conversations past and present regarding namespaces as well as link to a number of third party articles/blog-entries that discuss namespaces (for those that might be interested in finding out a little more about how namespaces are being recieved in the wild.)

Why this document

This document serves as summary of outstanding issues in order to aid discussion and resolution thereof.

Common Misconceptions

This document does not serve to force any particular changes in the engine regarding namespaces, as such any or all of the issues defined may at some stage be declared resolved without any implementation changes; It should accepted that some issues may only exist in so far that users have misinterpreted the current namespace functionality.

It is not the intention of this document to prove namespaces are either useless or counter-productive. On the contrary it is the aim of this document to aid the resolution of a number issues (percieved or otherwise) in the hope that this will result in the best possible implementation prior to it's first official release, whereby a positive addition to the language will be introduced that is also perceived to be as such. With that in mind, thanks are extended to the developers who are responsible for the namespace implementation thus far ... without them we would have nothing!

Issue Resolution

It is envisaged that all the issues raised in this document will be resolved in one of the following ways:

  1. via functional changes to the current implementation
  2. via the introduction of functional limitations (e.g. E_WARNING, E_PARSE or E_FATAL errors) that alert php users to problems with there use of namespaces
  3. via user education, to this end a seperate document is being developed in order to define guidelines and 'best practices' with regard to namespaces (see: namespaces)

Issues

The following issues have been put forwards by various members of the php developers group and php users at large, the issues are covered in the following sections:

  1. 1. global & namespaced code in one file
  2. 2. define() & defined()
  3. 3. Autoload & functions
  4. 4. You can use anything
  5. 5. Importing NameSpace::*
  6. 6. Static methods v. namespaced function ambiguities
  7. 7. Class constants v. namespaced constants ambiguities
  8. 8. use and includes
  9. 9. Importing functions
  10. 10. Name resolution order
  11. 11. Keywords in namespace names
  12. 12. Namespace must be first declaration in file
  13. 13. Namespaces aren't implemented like in ...

1. global & namespaced code in one file

currently one can declare multiple namespaces per file, but it is not possible to have code in the global scope in a file that declares namespaces, this is seen by some as an artificial limitation that forces some developers to change their project structures and as such breaks system that make use of (automated) source file concatenation (for performance reasons & distrubition), this is issue is being tackled in a seperate rfc and won't be covered here. (see namespacecurlies)


2. define() & defined()

currently one can declare constants in namespaces (in the same way as can be done in classes) as well as using the define() function inside namespaced code, but problems arise due to inconsistencies, these are:

  • constants are case-sensitive, but namespaces are case-insensitive.
  • defined() is not aware of namespace aliases.
  • the namespace part of constants defined with const are lowercased.

the following code tries to demonstrate the issues:

ns.inc:

<?php
namespace MY::TEST::NS;
 
// compile time namespaced constant
const DEBUG_NS = true;
// runtime global constant defined in namespaced code
define('DEBUG', true);
// runtime namespaced constant defined in namespaced code
define(__NAMESPACE__.'::DEBUG_2', true);
?>

test1.php:

<?php
// include namespaced code
include './ns.inc';
// declare an alias for the namespace
use MY::TEST::NS as MTN;
// perform some tests
echo "defined('DEBUG'): "                 .(defined('DEBUG')                  ? 'YES' : 'NO')." (expect YES)\n";
echo "defined('MY::TEST::NS::DEBUG_2'): " .(defined('MY::TEST::NS::DEBUG_2')  ? 'YES' : 'NO')." (expect YES)\n";
echo "defined('my::test::ns::DEBUG_2'): " .(defined('my::test::ns::DEBUG_2')  ? 'YES' : 'NO')." (expect NO)\n";
echo "defined('my::test::ns::debug_2'): " .(defined('my::test::ns::debug_2')  ? 'YES' : 'NO')." (expect NO)\n";
echo "defined('MY::TEST::NS::DEBUG_NS'): ".(defined('MY::TEST::NS::DEBUG_NS') ? 'YES' : 'NO')." (expect YES)\n";
echo "defined('my::test::ns::DEBUG_NS'): ".(defined('my::test::ns::DEBUG_NS') ? 'YES' : 'NO')." (expect NO)\n";
echo "defined('my::test::ns::debug_ns'): ".(defined('my::test::ns::debug_ns') ? 'YES' : 'NO')." (expect NO)\n";
echo "defined('MTN::DEBUG_NS'): "         .(defined('MTN::DEBUG_NS')          ? 'YES' : 'NO')." (expect YES)\n";
echo "defined('MTN::DEBUG_2'): "          .(defined('MTN::DEBUG_2')           ? 'YES' : 'NO')." (expect YES)\n";
echo "defined('mtn::DEBUG_NS'): "         .(defined('mtn::DEBUG_NS')          ? 'YES' : 'NO')." (expect YES)\n";
echo "defined('mtn::DEBUG_2'): "          .(defined('mtn::DEBUG_2')           ? 'YES' : 'NO')." (expect YES)\n";
?>

test1.php output with expected results given in brackets:

defined('DEBUG'): YES (expect YES)
defined('MY::TEST::NS::DEBUG_2'): NO (expect YES)
defined('my::test::ns::DEBUG_2'): NO (expect NO)
defined('my::test::ns::debug_2'): NO (expect NO)
defined('MY::TEST::NS::DEBUG_NS'): YES (expect YES)
defined('my::test::ns::DEBUG_NS'): YES (expect NO)
defined('my::test::ns::debug_ns'): NO (expect NO)
defined('MTN::DEBUG_NS'): NO (expect YES)
defined('MTN::DEBUG_2'): NO (expect YES)
defined('mtn::DEBUG_NS'): NO (expect YES)
defined('mtn::DEBUG_2'): NO (expect YES)

test2.php:

<?php
// include namespaced code
include './ns.inc';
// declare an alias for the namespace
use MY::TEST::NS as MTN;
// output declared constants
$cnsts = get_defined_constants(true);
var_dump($cnsts['user']);
?>

test2.php actual output:

array(3) {
  ["my::test::ns::DEBUG_NS"]=>
  bool(true)
  ["DEBUG"]=>
  bool(true)
  ["MY::TEST::NS::DEBUG_2"]=>
  bool(true)
}

test2.php expected output:

array(3) {
  ["MY::TEST::NS::DEBUG_NS"]=>
  bool(true)
  ["DEBUG"]=>
  bool(true)
  ["MY::TEST::NS::DEBUG_2"]=>
  bool(true)
}

test3.php:

<?php
// include namespaced code
include './ns.inc';
// declare an alias for the namespace
use MY::TEST::NS as MTN;
// attempt to use constants directly
var_dump(
    'the following are expected to be TRUE',
    (DEBUG === true),
    (MTN::DEBUG_NS === true),
    (MY::TEST::NS::DEBUG_NS === true)
);
var_dump(
    'the following are expected to be FALSE',
    (debug === true),
    (mtn::DEBUG_NS === true),
    (my::test::ns::DEBUG_NS === true)
);
var_dump(
    'the following are expected to be TRUE (but give Fatal Error: Class not found)',
    '(MTN::DEBUG_2 === true)',
    '(MY::TEST::NS::DEBUG_2 === true)'
);
/*
var_dump(
    'the following are expected to be ??? (and give Fatal Error: Class not found)',
    '(MY::TEST::NS::debug_ns === true)',
    '(my::test::ns::debug_ns === true)',
    '(MY::TEST::NS::debug_2 === true)',
    '(my::test::ns::DEBUG_2 === true)',
    '(my::test::ns::debug_2 === true)',
    '(MTN::debug_ns === true)',
    '(mtn::debug_ns === true)',
    '(MTN::debug_2 === true)',
    '(mtn::DEBUG_2 === true)',
    '(mtn::debug_2 === true)'
);
//*/
?>

test3.php output:

string(37) "the following are expected to be TRUE"
bool(true)
bool(true)
bool(true)
string(38) "the following are expected to be FALSE"
bool(false)
bool(true)
bool(true)
string(60) "the following are expected to be TRUE (but give fatal error)"
string(23) "(MTN::DEBUG_2 === true)"
string(32) "(MY::TEST::NS::DEBUG_2 === true)"

the above examples raise the following questions:

  • which of the inconsistencies can be resolved through documentation?
  • which of the inconsistencies can be resolved through changes to the implementation?
  • given the potential for confusion, and the potential difficulty of implementing a solution, is it worth keeping the ability to define constants (with const) directly in namespaces?

3. Autoload & functions

NB: the 'issue' demonstrated below was factually incorrect, the issue is left here as an illustration of how easy it is to misinterpret the working of the namespace function (thereby showing how important it is that a comprehensive guideline is made available, regardless of any changes in implementation that may yet occur). an explaination of the misinterpretation is given at the end of this section.

The engine does not support the autoloading of functions, additionally it is not currently possible to alias functions via the use statement (a seperate issue). It has been suggested that the way to use namespaced functions is as follows (example1.php):

ns_funcs.inc (serves as the namespaced include file for all the examples in this section):

<?php
namespace MY::TEST::NS;
 
function tryme() { echo "hello world from ".__FUNCTION__."!\n"; }
 
class Test { function tryme() { echo "hello world from ".__METHOD__."!\n"; }}
 
// simple echo statement to show the file has been included
// this echo statement does not effect the behaviour of any of the relevant tests
// (test this yourself by removing it!) 
echo __FILE__,' containing ',__NAMESPACE__," included\n";
<php>
 
example1.php
<code php>
<?php
include './ns_funcs.inc';
use MY::TEST::NS as MTN;
 
MTN::tryme();

output form example1.php

<PATH>/ns_funcs.inc containing MY::TEST::NS included
hello world from MY::TEST::NS::tryme!

example1.php works displaying the 'hello world' message, additionally __FUNCTION__ displays the fully qualified name of the function as would be expected.

something strange happens when we replace the simple include statement with a trivia __autoload() definition and rely on the use statement to trigger the inclusion of ns_funcs.php, the function is seemingly not available and we are confronted with a fatal error instead of the 'hello world' output message:

example2.php:

<?php
function __autoload($c) { include_once './ns_funcs.inc'; }
 
use MY::TEST::NS as MTN;
 
MTN::tryme();

output from example2.php

<PATH>/ns_funcs.inc containing MY::TEST::NS included

Fatal error: Class 'MY::TEST::NS' not found in <PATH>/funcs2.php on line 6

The problem doesn't have to do with the use of the alias (MTN), example3.php also demonstrates the fatal error:

example3.php:

<?php
function __autoload($c) { include_once './ns_funcs.inc'; }
 
use MY::TEST::NS as MTN;
 
MY::TEST::NS::tryme();

output from example3.php

<PATH>/ns_funcs.inc containing MY::TEST::NS included

Fatal error: Class 'MY::TEST::NS' not found in <PATH>/funcs2.php on line 6

We can magically make the function available merely by using a class in the autoloaded, aliased namespace:

example4.php:

<?php
function __autoload($c) { include_once './ns_funcs.inc'; }
 
use MY::TEST::NS as MTN;
 
$test = new MTN::Test;
 
MY::TEST::NS::tryme();

output from example4.php

<PATH>/ns_funcs.inc containing MY::TEST::NS included
hello world from MY::TEST::NS::tryme!

The problem illustrated above demonstrates a bug in the engine related to autoloading as triggered by use statements that it's very easy to make the incorrect assumption that use statements are performed at run-time (and trigger autoloading) whereas in fact they are performed at compile time and do not trigger autoloading, the following points are put forward:

  • use statements cannot differentiate between that alias namespaced classes and those that alias namespaces.
  • use statements are not checked to see if they reference a valid namespace or namespaced class (this issue is also described seperately below)
  • one can only autoload namespaces, but it is only usable when using namespaced classes.

4. You can 'use' anything

When trying to use an undefined class or function the engine will respond with a fatal error (after an attempt to autoload in the case of a class), this is not the case with the use statement (although it does trigger autoloading if an autoloader is defined), this seems inconsistent and unhelpful, the expectation would be that an unresolvable use statement would give a fatal error, the following code tries to demonstrate the issue, example1.php use autoloading, example2.php does not, the output is the same for both:

ns.inc:

<?php
 
namespace MY::TEST::NS;
 
class Test { function tryme() { echo "hello world from ".__METHOD__."!\n"; }}
 
// simple echo statement to show the file has been included
// this echo statement does not effect the behaviour of any of the relevant tests
// (test this yourself by removing it!)
echo __FILE__,' containing ',__NAMESPACE__," included\n";
?>

example1.php

<?php
function __autoload($c) { include_once './ns.inc'; }
 
use MY::TEST::FOO::NS as FOOBAR;
 
$test = new MY::TEST::NS::Test;
$test->tryme();
?>

example2.php

<?php
include_once './ns.inc'; 
 
use MY::TEST::FOO::NS as FOOBAR;
 
$test = new MY::TEST::NS::Test;
$test->tryme();
?>

output for both example1.php and example2.php:

<PATH>/ns.inc containing MY::TEST::NS included
hello world from MY::TEST::NS::Test::tryme!

It was incorrectly presumed that use statements trigger autoloading, which is not the case, nonetheless the lack of engine feedback on invalid and/or unused use statements could be considered counter-productive from a developer point of view. It should be possible, however, to keep track of which use statements were declared and throw a parse error (E_PARSE) for any that have not been 'used' before the end of the file is reached.

Questions:

  • is the addition of a parse error for unused use statements wanted?
  • is it viable to implement?
  • what effect would included files have? would they need to be considered when implementing this?

5. Importing NameSpace::*

It is not possible to import everything from a namespace with a single use statement, the following code demonstrates what is meant:

<?php
use MY::TEST::NS::*;

Some people are worried this will lead to inordinately large lists of use statements having to be added to files that make use of namespaced code, with the consequence of decreased readability and the increased likelihood of typing errors. The counter argument is that importing everything from a namespace is bad practice and that not allowing the importing of everything in a namespace in a single statement forces the developer to think about what he wants to actually use (leading to better performing code).

There is a work around using the (as yet undocumented) class_alias() function:

ns_import.inc:

namespace MY::TEST:NS;
 
function import($prefix)
{
   class_alias(__NAMESPACE__.'::One',   $prefix.'::One');
   class_alias(__NAMESPACE__.'::Two',   $prefix.'::Two');
   class_alias(__NAMESPACE__.'::Three', $prefix.'::Three');
}
 
class One   {};
class Two   {};
class Three {};

example1.php:

include 'ns_import.inc';
MY::TEST:NS::import('MTN');
 
var_dump(new MTN::One, new MTN::Two, new MTN::Three);

output of example1.php:

object(MY::TEST::NS::One)#1 (0) {
}
object(MY::TEST::NS::Two)#2 (0) {
}
object(MY::TEST::NS::Three)#3 (0) {
}

The question is: should we allow importing of everything in a namespace or accept that people will use the above mentioned work-around (which I believe probably will happen)? regardless one can consider this issue a philosophical one, rather than one caused by an unintentioned limitation in the namespace implementation. If importing of everything via a single use statement is added as engine functionality other issues are raised regarding what would occur with namespaced functions and constants.


6. Static methods/namespaced function ambiguities

There is an abiguity, from the users point of view between static class method calls and namespaced function calls, essentially it is very difficult to determine (if at all) from the code, even given context, whether TEST::what(); (from example1.php below) is a static method call or a namespaced function call. The statement could, in this case, be either, and which ever it is the other has been rendered unusable, the code below demonstrates:

class.inc:

<?php
class TEST {
    static function what()  { echo __FUNCTION__," in class\n"; }
    static function where() { echo __FUNCTION__," in class\n"; }
}
?>

ns.inc:

<?php
namespace TEST;
function what() { echo __FUNCTION__," in namespace\n"; }
?>

example1.php:

<?php
include './class.inc';
include './ns.inc';
TEST::what();
TEST::where();
?>

output of example1.php (regardless of include order):

TEST::what in namespace
where in class

There is no way to reference the static method TEST::what(), additionally because static method TEST::where() is reachable one is left with the potential that the namespaced include will break current code if a where() function is later defined in the TEST namespace.

There is a need to disambiguate these two calls, and to be able to call both regardless of the existence of the other.


7. Class constants v. constants ambiguities

The same ambiguity that exists between static methods and namespaced functions also exists between class constants and namespaced constants. From the users point of view it not possible to determine, with any easy or certainty, from the code whether TEST::MY_CONST_ONE (from example1.php below) is a class constant or a namespaced constant. The statement could, in this case, be either, and which ever it is the other has been rendered unusable, the code below demonstrates:

class.inc:

<?php
class TEST {
    const MY_CNST_ONE = 'TEST class CONSTANT ONE';
    const MY_CNST_TWO = 'TEST class CONSTANT TWO';
}
?>

ns.inc:

<?php
namespace TEST;
const MY_CNST_ONE = 'TEST class CONSTANT ONE';
?>
 
example1.php:
<code php>
<?php
include './class.inc';
include './ns.inc';
echo TEST::MY_CNST_ONE, "\n";
echo TEST::MY_CNST_TWO, "\n";
?>

output of example1.php (regardless of include order):

TEST namespace CONSTANT ONE
TEST class CONSTANT TWO

There is no way to reference the constant MY_CNST_ONE from class TEST, additionally because constant MY_CNST_TWO from class TEST is reachable one is left with the potential that the namespaced include will break current code if a constant MY_CNST_TWO is later defined in the TEST namespace, regardless it introduces confusion because one is it possible to retrieve constants from two different 'places' using the exact same prefix/syntax.

There is a need to disambiguate the constants, and to be able to reference both regardless of the existence of the other.


8. **use** and includes

Users are currently able and used to be able to include code, especially inside a loop, that makes use of the “includer's” variables and state in order to do something, very often this relates to some kind of templated output generation ... the reason to use an include file as opposed to a function often revolves around the issue of having alot of textual or HTML output which some find less well suited to being contained inside a function, additionally complex logic that would allow such an include file to be used in disparate circumstances would become messy in terms of function argument if a function was used instead.

It is fairly obvious that passing declared use statements to an include file that was itself namespaced is not a logical step to take, if only because the concept of a namespaced file generally points to library-like declarations (functions, classes, constants) rather than directly run code.

On the other hand the expectation from users that are including 'processing code' is likely to be that declared aliases are passed along as well as any variables defined in the scope of the code that performs the inclusion.

Questions:

1. is it feasable to pass declared aliases to non-namespaced includes? 2. is it desirable? if not guidelines are likely to be required to explain how things work, why and how to tackle them. 3. is it possible to determine what aliases have been declared? if not then it's probably of no real benefit to be able pass declared aliases to non-namespaced includes, without the included file being able to determine what is in use it's capabilities in this respect are rather limited.

Chances are this is not a good idea, nonetheless details examples and documentation will probably be required in order to stem developer confusion, if nothing else confusion will limit uptake (as a rule users generally don't make use of functionality they either don't understand or misunderstand)


9. Importing functions

It is not currently possible to alias namespaced functions, making them inconsistent with namespaced classes, and forcing users that are working with namespaced functions to always prefix namespaced functions in order to use them. This seems like an artificial limitation that implies functions are a second-class after thought as far as namespaces are concerned, additionally php has never before dictated to users an OO over procedural style of coding, the current implementation of namespaces seems to imply that OO is inherently better.

It is therefore not possible to override built in functions with functions imported from a namespace, which some people has expressed a desire to do ... most notably in the context of template engines, which generally strive to hide as much of the php's syntax from template developers [who generally don't program php] even though the template engine actually uses php syntax/code to expose it's functionality) ... forcing template developers to learn the intricacies of prefixing functions they employ (and there by having to realise that these may clash with static methods!) creates an unnecessary burden.

Regardless, it should be possible to import a namespaced function into the current file and use it in the same way one has been accustomed to calling functions. The following examples tries to demonstrate the issue:

ns_funcs.inc:

<?php
namespace MY::TEST::NS;
function foo() { echo "Hello World!\n"; }
?>

example1.php:

<?php
include './ns_funcs.php';
// use MY::TEST::NS::foo;
use MY::TEST::NS;
NS::foo();
MY::TEST::NS::foo();
?>

output from example1.php:

Hello World!
Hello World!

example2.php:

<?php
include './ns_funcs.php';
use MY::TEST::NS::foo;
foo();
?>

output from example2.php:

Fatal error: Call to undefined function foo() in <PATH>/example2.php on line 4

10. Name resolution order


11. Keywords in namespace names

It is stated that namespace names serve simply as string replacements to unqualified [namespaced] class, function and constant names, which suggests that '::' that is often seen in the namespace names of example code is essentially meaningless, merely offering a visual aid to the user of namespaced code as to the intended structure of the entities defined within, as opposed to actually defining a semantic nesting of namespaced code:

example1.php:

<?php
namespace MY::PROJECT;
class App {}
namespace MY::PROJECT::DB;
class DB {}
namespace MY::PROJECT::MVC;
class Model {}
class View {}
class Controller {}
namespace MY::PROJECT::MVC::MODELS;
class Product {}
class Customer {}
class Order {}
?>

the preceeding example offers, according to current documentation, syntactic sugar that denotes how a project/codebase is structured without actually creating that structure. Yet the engine seems to actually parse namespace name piece by piece (e.g. 'MY', 'PROJECT', 'MVC' and 'MODELS') rather than treating the namespace name as an arbitrary string, the following demonstrates what happens when a keyword is incoporated:

example2.php:

<?php
namespace MY::PROJECT::STATIC::STUFF;
// some code
?>

output of example2.php:

Parse error: syntax error, unexpected T_STATIC, expecting T_STRING in <PATH>/example2.php on line 2

Essentially the engine is smarter about namespace names and aliases thereof than it is letting on, it's an almost certainty that the only issue here is lack of or somewhat misleading documentation (It's also fairly clear that this lends itself to a nested namespace implementation if that is ever seriously proposed). Below is a small example script demonstrating the engine's 'smarts'.

example3.php:

<?php
namespace MY::TEST::NS;
class hi {}
 
namespace MY__TEST__NS;
class hi {}
 
namespace THIRD;
use MY::TEST;
use MY::TEST::NS;
 
$a = new TEST::NS::hi;     // 'for' $a and $b the engine is smart enough to do MY::TEST::NS::hi,
$b = new NS::hi;           // something that can't be done with MY__TEST__NS.
$c = new MY__TEST__NS::hi; 
var_dump($a, $b, $c);
?>

output of example3.php:

object(MY::TEST::NS::hi)#1 (0) {
}
object(MY::TEST::NS::hi)#2 (0) {
}
object(MY__TEST__NS::hi)#3 (0) {
}

12. Namespace must be first declaration in file

Currently if you wish to declare one or more namespaces in a file nothing may preceed the initial namespace declaration, with the exception of white-space & comments between the initial php parser tag (<?php) and the initial namespace declaration (one can include as many comment blocks as one want's preceeding the initial namespace declaration in a file) .

Two seperate types of preceeding 'code' both cause fatal errors, both of which seem to be an unnatural restrictions:

  • Global Code
  • Inline Output

Global Code

No code may preceed a namespace declaration, given that php has never laid restriction or placed any requirement on code or file layout before and given that the php namespace functionality explicitly does not attempt to be a package like mechanism (i.e. there is no direct 1 to 1 relationship between files and namespaces that the engine can enforce or rely on), it seems unduly restrictive and counter-intuitive that the following two examples are not functionally identical (the second example results in a fatal error):

example1.inc

<?php
namespace MY::TEST::NS;
class Foo {}
?>

example1.php

<?php
echo "in the global scope!\n";
include './example1.inc';
?>

example2.php

<?php
echo "in the global scope!\n";
namespace MY::TEST::NS;
class Foo {}
?>

Inline Output

No output may occur, whitespace or otherwise, prior to the opening php parser tag, in a file that declares one or more namespaces. Again this seems unduly restrictive, granted it may not be good practice to have such output in files that declare namespaces, but there is no technical limitation that warrants it either, one could also argue that unintentional output (e.g. an unintentional space) is somewhat less painful to the functioning of a body of code than a fatal error. The following example demostrates a file that triggers the fatal error:

example3.php

 <?php
namespace MY::TEST::NS;
class Foo {}
 
?>

13. Namespaces aren't implemented like in ...

PHP is not <insert your favorite language here>. Granted this is not an issue, but some of you reading this probably need something to smile about after reading the items above!

Patches & Proposal

The general proposal of this RFC is that discussion regarding the namespace implementation continues in order to resolve major issues in one way or other, additionally a number of patches have already been made available, these are listed below:

Issue's 6 & 7

This patch addresses the issues regarding resolution ambiguities, as defined in issue 6. “Static methods/namespaced function ambiguities” and issue 7. “Class constants v. constants ambiguities”.

To quote the author from his original post regarding this patch:

DISCLAIMER: the attached patch will need some work from the ZE experts, this is my first attempt at meddling with opcodes, and I'm sure that there is a better solution than adding 2 new opcodes, since all we really need to do is pass what amounts to a 1/0 flag in telling function/constant resolution to default to namespace function/constant rather than class method/constant.

The attached patch against PHP_5_3 demonstrates a working implementation of the changes I proposed. Name resolution for functions/constants now works as follows:

1) class method/constant is checked first
2) namespace function/constant is checked iff #1 does not succeed

If a fully qualified name is prefixed with function:: or const:: it will only check the namespace function/const. Here is a test demonstrating how it works:

ns_071.inc:
<?php
namespace foo;
function func() {
   echo "namespace function\n";
}
function two() {
   echo "namespace function two\n";
}
const one = "one\n";
const two = "two\n";
?>


ns_071.phpt:

--TEST--
071: name conflict, function/static method, constant/class constant
--FILE--
<?php
include __DIR__ . '/ns_071.inc';
class foo {
   const one = "won\n";
   static function func() {
       echo "static method\n";
   }
}
foo::two();
function::foo::func();
foo::func();
echo foo::one;
function::foo::func();
echo const::foo::one;
echo foo::two;
?>
===DONE===
--EXPECT--
namespace function two
namespace function
static method
won
namespace function
one
two
===DONE===

Issue 9

This patch addresses the issues regarding the inability to alias functions to simple names, as defined in issue 9. “Importing functions”

Issue 12

This patch addresses the inability to include [html] output prior to the first <?php tag, in a namespaced file, as defined in issue 12. “Namespace must be first declaration in file”

To quote the author from his original post regarding this patch:

This is a simple patch that allows files like this to work without parse error.:

main.php:
<html>
<head>
<title>template example</title>
</head>
<body>
<?php
namespace my::template;
 
// stuff
 
?>
</body>
</html>

Miscellaneous

Discussions past & present

Below is a list of links to internals@lists.php.net thread that discuss (amongst others things) namespaces, the list is in reverse chronological order (hopefully) based on the initial post to the given thread and only lists discussion that have occurred in 2008:

Nothing has been filtered on the basis of relevance BUT some threads may not be listed due to the 'limitations' of the marc.info search functionality!

Additional Commentary

the articles & blog posts listed here are (hopefully) in reverse chronological order, please note that older items may no longer be relevant as the implementation has changed since the time the item was published:

and way back when 5.0 was still in incubation:

this particular assessment of the original php5.0 namespace implementation (which was scraped), might be of interest to compared issues raised then with those currently being raised:

for the really keen ones amongst us, knock yourself out:

rfc/namespaces.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1