Dennis' note is irrelevant as of today : with last 5.3 builds it is possible to use class names which coincide with PHP's internal class names within your namespaces. His example using PDO now works correctly.
Règles de résolution de noms
Les noms sont résolus suivant ces règles de résolution :
-
Toutes les noms qualifiés sont traduis au moment de la compilation
suivant les règles d'importation courantes. Par exemple, si l'espace
de noms A::B::C est importé, un appel à
C::D::e()est traduis enA::B::C::D::e(). -
Les noms de classes non-qualifiés sont traduis au moment de la compilation
suivant les règles d'importation courantes (les noms complets sont substitués
par le nom court importé). Par exemple, si l'espace de noms A::B::C
est importé,
new C()est traduit ennew A::B::C(). - Dans un espace de noms, les appels aux fonctions non-qualifiées qui sont définies dans l'espace de noms courant (et qui sont connues au moment où l'appel est analysé), sont interprétés comme des appels aux fonctions de l'espace de noms, au moment de la compilation.
-
Dans un espace de noms (comme A::B), les appels aux fonctions non-qualifiées
qui ne sont pas définies dans l'espace de noms courant sont résolus au
moment de la compilation. Voici comme un appel à la fonction
foo() est résolu :
- On recherche une fonction depuis l'espace de noms courant : A::B::foo().
- Ensuite, on tente de chercher et d'appeler la fonction interne foo().
-
Dans un espace de noms (comme A::B), les appels aux noms de classes
non-qualifiées sont résolus au moment de l'exécution. Voici comment un appel à
new C()est résolu :- On recherche une classe depuis l'espace de noms courant : A::B::C.
- Ensuite, on tente de chercher et d'appeler la classe interne C.
- Puis, on charge automatiquement A::B::C.
new ::C()doit être utilisé. -
Les appels aux fonctions qualifiées sont résolues au moment de l'exécution.
Voici comment un appel à A::B::foo() est résolu :
- On recherche une fonction foo() dans l'espace de noms A::B.
- Puis, on cherche une classe A::B et on appelle sa méthode statique foo(). On charge automatiquement la classe si nécessaire.
-
Les noms de classes qualifiés sont résolus au moment de la compilation comme
une classe depuis l'espace de noms correspondant. Par exemple,
new A::B::C()se réfère à la classe C depuis l'espace de noms A::B.
Exemple #1 Illustration de la résolution de nom
<?php
namespace A;
// Appels de fonctions
foo(); // Tout d'abord, on tente d'appeler "foo", définie dans l'espace de noms "A"
// puis, on appèle la fonction interne "foo"
::foo(); // Appel de la fonction "foo", définie dans l'espace global
// Références des classes
new B(); // Tout d'abord, on tente de créer un objet de la classe "B", défini dans l'espace
// de noms "A", puis, on crée l'objet dans la classe interne "B"
new ::B(); // On crée un objet de la classe "B", défini dans l'espace global
// fonctions statiques de méthodes et d'espace de noms depuis un autre espace de noms
B::foo(); // Tout d'abors, on tente d'appeler la fonction "foo" depuis l'espace de noms "A::B",
// puis, on appèle la méthode "foo" de la classe interne "B"
::B::foo(); // Tout d'abord, on tente d'appeler la fonction "foo" depuis l'espace de noms "B",
// puis, on appèle la méthode "foo" de la classe "B" depuis l'espace global
// fonctions statiques de méthodes et d'espace de noms depuis l'espace de noms courant
A::foo(); // Tout d'abord, on tente d'appeler la fonction "foo" depuis l'espace de noms "A::A",
// puis, on tente d'appeler la méthode "foo" de la classe "A" depuis l'espace de noms "A",
// puis, on tente d'appeler la fonction "foo" depuis l'espace de noms "A",
// puis, on appèle la méthode "foo" de la classe interne "A"
::A::foo(); // Tout d'abord, on tente d'appeler la fonction "foo" depuis l'espace de noms "A",
// puis, on appèle la méthode "foo" de la classe "A" depuis l'espace global
?>
Règles de résolution de noms
Raphael
26-Mar-2008 07:01
26-Mar-2008 07:01
Will
21-Feb-2008 12:08
21-Feb-2008 12:08
Agreed. Dennis is right on with this. To add on, requiring each file that includes a namespace also defeats the purpose of namespacing. It makes more sense if you have a repository for namespaces and just use those.
Example:
/some/path/to/namespaces/
<?php
use Some::Namespace;
// Test is withing Namespace.
$t = new Test();
// Test2 is not, so it checks includes, etc.
$t = new Test2();
?>
Dennis
04-Jan-2008 03:18
04-Jan-2008 03:18
Sadly enough, the latest class name resolution rules render PHP namespaces quite useless. It is impossible to use class names which coincide with PHP's internal class names within your namespaces unless you _explicitly_ use them and alias them!
The worst thing is that PHP internal class names _always_ will take precedence over your class names. This means that you start developing a toolkit and take good care to use and alias your class names (eg, Exception or DateTime or PDO). You also create classes with names that don't have names that would conflict with PHP's internal classes. However, after you have done lots of work on your toolkit you find out that there's been another extension added to PHP and it has a class that coincides with your class name. Your code becomes useless.
A quick example:
<?php
/*
* (PDO.php)
*/
namespace my::name::space;
class PDO {}
?>
<?php
/*
* (Test.php)
*/
namespace my:name::space;
class Test {
static function doSmth() {
$pdo = new PDO();
}
}
?>
and this code:
<?php
include('PDO.php');
include('Test.php');
use my::name::space::Test;
Test::doSmth();
?>
This of course will emit a warning that PDO constructor expects at least one parameter (which is perfectly correct for PHP Data Objects). Now go to your php.ini and disable lines
extension=php_dll.php
or
extension=pdo.so
as well as all other PDO drivers. Now run the example and it will produce no warnings!
I have used PDO class name here as it can be easily disabled to demonstrate the problem. Now imagine that PDO was not an internal class and you were using it in your code for some time already. Suddenly an extension author choses to use this name. And all your code is broken. You will have to go into every file that references that class and explicitly use it with an alias and rename all occurences of this class name to an alias.
As to me this is too far from solving the name collision issues!
