mirror of
https://github.com/php/php-src.git
synced 2024-09-21 18:07:23 +00:00
- Merge minor namespace related stuff (README and tokenizer)
This commit is contained in:
parent
f37e408ed8
commit
059b506d38
174
README.namespaces
Executable file
174
README.namespaces
Executable file
@ -0,0 +1,174 @@
|
||||
Design
|
||||
======
|
||||
|
||||
Main assumption of the model is that the problem that we are to solve is the
|
||||
problem of the very long class names in PHP libraries. We would not attempt
|
||||
to take autoloader's job or create packaging model - only make names
|
||||
manageable.
|
||||
|
||||
Namespaces are defined the following way:
|
||||
|
||||
Zend/DB/Connection.php:
|
||||
<?php
|
||||
namespace Zend::DB;
|
||||
|
||||
class Connection {
|
||||
}
|
||||
|
||||
function connect() {
|
||||
}
|
||||
?>
|
||||
|
||||
Namespace definition does the following:
|
||||
All class and function names inside are automatically prefixed with
|
||||
namespace name. Inside namespace, local name always takes precedence over
|
||||
global name. Several files may be using the same namespace.
|
||||
The namespace declaration statement must be the very first statement in
|
||||
the file. The only exception is "declare" statement that can be used before.
|
||||
|
||||
Every class and function in a namespace can be referred to by the full name
|
||||
- e.g. Zend::DB::Connection or Zend::DB::connect - at any time.
|
||||
|
||||
<?php
|
||||
require 'Zend/Db/Connection.php';
|
||||
$x = new Zend::DB::Connection;
|
||||
Zend::DB::connect();
|
||||
?>
|
||||
|
||||
Namespace or class name can be imported:
|
||||
|
||||
<?php
|
||||
require 'Zend/Db/Connection.php';
|
||||
import Zend::DB;
|
||||
import Zend::DB::Connection as DbConnection;
|
||||
|
||||
$x = new Zend::DB::Connection();
|
||||
$y = new DB::connection();
|
||||
$z = new DbConnection();
|
||||
DB::connect();
|
||||
?>
|
||||
|
||||
import statement only defines name aliasing. It may create name alias for
|
||||
namespace or class. The simple form of statement "import A::B::C::D;" is
|
||||
equivalent to "import A::B::C::D as D;". Import statement can be used at any
|
||||
time in the global scope (not inside function/class) and takes effect from
|
||||
the point of definition down to the end of file. It is recommended however to
|
||||
place imports at the beginning of the file. Import statements have effect
|
||||
only on the file where they appear.
|
||||
|
||||
The special "empty" namespace (:: prefix) is useful as explicit global
|
||||
namespace qualification. All class and function names started from ::
|
||||
interpreted as global.
|
||||
|
||||
<?php
|
||||
namespace A::B::C;
|
||||
|
||||
$con = ::mysql_connect(...);
|
||||
?>
|
||||
|
||||
A special constant __NAMESPACE__ contains the name of the current namespace.
|
||||
It can be used to construct fully-qualified names to pass them as callbacks.
|
||||
|
||||
<?php
|
||||
namespace A::B::C;
|
||||
|
||||
function foo() {
|
||||
}
|
||||
|
||||
set_error_handler(__NAMESPACE__ . "::foo");
|
||||
?>
|
||||
|
||||
In global namespace __NAMESPACE__ constant has the value of empty string.
|
||||
|
||||
Names inside namespace are resolved according to the following rules:
|
||||
|
||||
1) all qualified names are translated during compilation according to
|
||||
current import rules. So if we have "import A::B::C" and then "C::D::e()"
|
||||
it is translated to "A::B::C::D::e()".
|
||||
2) unqualified class names translated during compilation according to
|
||||
current import rules. So if we have "import A::B::C" and then "new C()" it
|
||||
is translated to "new A::B::C()".
|
||||
3) inside namespace, calls to unqualified functions that are defined in
|
||||
current namespace (and are known at the time the call is parsed) are
|
||||
interpreted as calls to these namespace functions.
|
||||
4) inside namespace, calls to unqualified functions that are not defined
|
||||
in current namespace are resolved at run-time. The call to function foo()
|
||||
inside namespace (A::B) first tries to find and call function from current
|
||||
namespace A::B::foo() and if it doesn't exist PHP tries to call internal
|
||||
function foo(). Note that using foo() inside namespace you can call only
|
||||
internal PHP functions, however using ::foo() you are able to call any
|
||||
function from the global namespace.
|
||||
5) unqualified class names are resolved at run-time. E.q. "new Exception()"
|
||||
first tries to use (and autoload) class from current namespace and in case
|
||||
of failure uses internal PHP class. Note that using "new A" in namespace
|
||||
you can only create class from this namespace or internal PHP class, however
|
||||
using "new ::A" you are able to create any class from the global namespace.
|
||||
6) Calls to qualified functions are resolved at run-time. Call to
|
||||
A::B::foo() first tries to call function foo() from namespace A::B, then
|
||||
it tries to find class A::B (__autoload() it if necessary) and call its
|
||||
static method foo()
|
||||
7) qualified class names are interpreted as class from corresponding
|
||||
namespace. So "new A::B::C()" refers to class C from namespace A::B.
|
||||
|
||||
Examples
|
||||
--------
|
||||
<?php
|
||||
namespace A;
|
||||
foo(); // first tries to call "foo" defined in namespace "A"
|
||||
// then calls internal function "foo"
|
||||
::foo(); // calls function "foo" defined in global scope
|
||||
?>
|
||||
|
||||
<?php
|
||||
namespace A;
|
||||
new B(); // first tries to create object of class "B" defined in namespace "A"
|
||||
// then creates object of internal class "B"
|
||||
new ::B(); // creates object of class "B" defined in global scope
|
||||
?>
|
||||
|
||||
<?php
|
||||
namespace A;
|
||||
new A(); // first tries to create object of class "A" from namespace "A" (A::A)
|
||||
// then creates object of internal class "A"
|
||||
?>
|
||||
|
||||
<?php
|
||||
namespace A;
|
||||
B::foo(); // first tries to call function "foo" from namespace "A::B"
|
||||
// then calls method "foo" of internal class "B"
|
||||
::B::foo(); // first tries to call function "foo" from namespace "B"
|
||||
// then calls method "foo" of class "B" from global scope
|
||||
?>
|
||||
|
||||
The worst case if class name conflicts with namespace name
|
||||
<?php
|
||||
namespace A;
|
||||
A::foo(); // first tries to call function "foo" from namespace "A::A"
|
||||
// then tries to call method "foo" of class "A" from namespace "A"
|
||||
// then tries to call function "foo" from namespace "A"
|
||||
// then calls method "foo" of internal class "A"
|
||||
::A::foo(); // first tries to call function "foo" from namespace "A"
|
||||
// then calls method "foo" of class "A" from global scope
|
||||
?>
|
||||
|
||||
TODO
|
||||
====
|
||||
|
||||
* Support for namespace constants?
|
||||
|
||||
* performance problems
|
||||
- calls to internal functions in namespaces are slower, because PHP first
|
||||
looks for such function in current namespace
|
||||
- calls to static methods are slower, because PHP first tries to look
|
||||
for corresponding function in namespace
|
||||
|
||||
* Extend the Reflection API?
|
||||
* Add ReflectionNamespace class
|
||||
+ getName()
|
||||
+ getClasses()
|
||||
+ getFunctions()
|
||||
+ getFiles()
|
||||
* Add getNamespace() methods to ReflectionClass and ReflectionFunction
|
||||
|
||||
* Rename namespaces to packages?
|
||||
|
@ -147,6 +147,9 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) {
|
||||
REGISTER_LONG_CONSTANT("T_DOLLAR_OPEN_CURLY_BRACES", T_DOLLAR_OPEN_CURLY_BRACES, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("T_CURLY_OPEN", T_CURLY_OPEN, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("T_PAAMAYIM_NEKUDOTAYIM", T_PAAMAYIM_NEKUDOTAYIM, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("T_NAMESPACE", T_NAMESPACE, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("T_IMPORT", T_IMPORT, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("T_NS_C", T_NS_C, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("T_DOUBLE_COLON", T_PAAMAYIM_NEKUDOTAYIM, CONST_CS | CONST_PERSISTENT);
|
||||
}
|
||||
|
||||
@ -272,6 +275,9 @@ char *get_token_type_name(int token_type)
|
||||
case T_DOLLAR_OPEN_CURLY_BRACES: return "T_DOLLAR_OPEN_CURLY_BRACES";
|
||||
case T_CURLY_OPEN: return "T_CURLY_OPEN";
|
||||
case T_PAAMAYIM_NEKUDOTAYIM: return "T_DOUBLE_COLON";
|
||||
case T_NAMESPACE: return "T_NAMESPACE";
|
||||
case T_IMPORT: return "T_IMPORT";
|
||||
case T_NS_C: return "T_NS_C";
|
||||
|
||||
}
|
||||
return "UNKNOWN";
|
||||
|
Loading…
Reference in New Issue
Block a user