PHP 5.3 - Namespaces

PHP
Enviado por Eclesiastes em Sex, 19/10/2007 - 10:26.PHP

Agora sim podemos testar o suporte a namespace no PHP5.3! Esta versão encontra-se para download apenas no http://snaps.php.net/ que é constantemente atualizada.

Segue abaixo a tradução do README.namespaces que vem junto à ele.

A principal abordagem deste modelo é o problema que temos com nomes muito grandes de classes em bibliotecas no PHP. Não devemos tomar o trabalho de autoloader ou criar modelo de pacotes - somente tornar nomes manuseáveis.

Namespaces são definidos da seguinte forma:

Zend/DB/Connection.php:

  1. <?php
  2. namespace Zend::DB;
  3.  
  4. class Connection {
  5. }
  6.  
  7. function connect() {
  8. }
  9. ?>

A definição do Namespace faz o seguinte:
Todos os nomes de classes e funções dentro são automaticamente prefixadas
com o nome do namespace. Em namespace, nomes locais sempre tem precedência
sobre nomes globais. Muitos arquivos podem ser usados no mesmo namespace.
A declaração do comando namespace precisa ser o primeiro comando no arquivo.
A única exceção é o comando "declare" que pode ser usado antes.

Toda classe e função em um namespace pode ser referênciado pelo nome completo
- e.g. Zend::DB::Connection ou Zend::DB::connect.

  1. <?php
  2. require 'Zend/Db/Connection.php';
  3. $x = new Zend::DB::Connection;
  4. Zend::DB::connect();
  5. ?>

Nome de classe ou namespace pode ser importado:

  1. <?php
  2. require 'Zend/Db/Connection.php';
  3. import Zend::DB;
  4. import Zend::DB::Connection as DbConnection;
  5.  
  6. $x = new Zend::DB::Connection();
  7. $y = new DB::connection();
  8. $z = new DbConnection();
  9. DB::connect();
  10. ?>

comando import somente define nome auxiliares. Ele pode criar apelidos para
namespace ou classe. A simples forma do comando "import A::B::C::D;" é
equivalente a "import A::B::C::D as D;". Comando import pode ser usado
no escopo global (fora de função/classe) e fazer efeito de onde foi definido
até o final do arquivo. É recomendado porém que coloque os imports no início
do arquivo. Comandos import tem efeito somente nos arquivos onde eles aparecem.

O namespace especial "vazio" (prefixo ::) é usado como especificação de
namespace global. Todo nome de classe e função iniciado com :: é interpretado
como global.

  1. <?php
  2. namespace A::B::C;
  3.  
  4. $con = ::mysql_connect(...);
  5. ?>

Uma constante especial __NAMESPACE__ contêm o nome do namespace atual.
Ela pode ser usada para construir nomes para passá-lo como callbacks.

  1. <?php
  2. namespace A::B::C;
  3.  
  4. function foo() {
  5. }
  6.  
  7. set_error_handler(__NAMESPACE__ . "::foo");
  8. ?>

No namespace global a constante __NAMESPACE__ tem como valor uma string vazia.

Os nomes dentro do namespace são analisados segundo as seguintes regras:

1) todo nome é traduzido durante a compilação de acordo com a atual regra do import.
Então se temos "import A::B::C" então "C::D::e()" é traduzido para "A::B::C::D::e()".

2) classes com nomes não qualificados são traduzidos durante compilação de acordo com
a atual regra do import. Então se nós temos "import A::B::C" então "C::D::e()" é
traduzido para "new A::B::C()".

3) no namespace, chamadas para não qualificadas funções que são definidas no
atual namespace (e é conhecida quando a chamada é analisada) são interpretadas
como chamadas da funções desse namespace.

4) no namespace, chamadas para não qualificadas funções que não são definidas
no atual namespace são resolvidas em run-time. A chamada para função foo()
dentro do namespace (A::B) primeiro tenta encontrar e chama a função do
atual namespace A::B::foo() e se não existir tenta chamar a função interna
foo(). Note que usando foo() no namespace você chama somente a função interna
do PHP, porém usando ::foo() você estará chamando alguma função do namespace global.

5) nomes não qualificados de classes são resolvidos em run-time. E.q. "new Exception()"
primeiro tenta usar (e autoload) a classe do atual namespace e em caso de falha usa
a classe interna do PHP. Note que usando "new A" no namespace, você pode criar classe
para este namespace ou classe interna do PHP, contudo usando "new ::A" você estará criando
uma classe para o namespace global.

6) chamadas para funções qualificadas são resolvidas em run-time. Chamada para "A::B::foo()"
primeiro tenta chamar a função foo() do namespace A::B, então tenta encontrar a classe
"A::B" (__autoload() se necessário) e chama seu método estático foo().

7) Nomes qualificados de classe são interpretados como classe do namespace correspondente.
Então "new A::B::C()" refere-se a class C do namespace A::B.

Exemplos
--------

  1. <?php
  2. namespace A;
  3. foo();   // primeiro tenta chamar "foo" definida no namespace "A"
  4.          // então chama a função interna "foo"
  5. ::foo(); // chama a função "foo" definida no escopo global
  6. ?>

  1. <?php
  2. namespace A;
  3. new B();   // primeiro tenta criar objeto da class "B" definida no namespace "A"
  4.            // então cria o objeto da classe interna "B"
  5. new ::B(); // cria objeto da classe "B" definida no escopo global
  6. ?>

  1. <?php
  2. namespace A;
  3. new A(); // primeiro tenta criar objeto da classe "A" do namespace "A" (A::A)
  4.          // então cria objeto da class interna "A"
  5. ?>

  1. <?php
  2. namespace A;
  3. B::foo();   // primeiro tenta chamar a função "foo" do namespace "A::B"
  4.             // então chama o método "foo" da classe interna "B"
  5. ::B::foo(); // primeiro tenta chamar a função "foo" do namespace "B"
  6.             // então chama o método "foo" da classe "B" do escopo global
  7. ?>
  8.  

Quanto ao uso do comando declare, eu verifiquei e não aconteceu o esperado segundo o texto acima. Reportei, e estam verificando.

Até a próxima pessoal!