PHP 5.3 parte I: Namespaces

Posted on dezembro 8, 2009. Filed under: PHP |

Muitos dos recursos previstos para a versão 6 do php foram incluídos na versão 5.3. Namespaces é uma delas. Namespaces vem para ajudar a evitar conflitos entre nome de funções, classes e constantes. Até a versão 5.2 muitas aplicações utilizavam prefixos nos nomes de classes e funções para evitar estes conflitos. Na aplicação de blog chamada wordpress, usa-se o prefixo “wp_” em nome dos elementos. Por exemplo o nome de algumas funções: wp_update_post, wp_create_user !
Com Namespaces você agrupa classes, funções e constante de forma que possa haver elementos com nomes iguais em diferentes “grupos” ou namespaces, funcionando sem conflitos. Dessa forma, pode-se diminuir a utilização de prefixos, deixando o código mais limpo.

Definindo Namespaces

Para definir um namespace com o nome de foo:
<?php
namespace foo;

Vamos montar um ambiente de testes para entender melhor o funcionamento de namespaces. Segue a abaixo a declaração de duas classes com o mesmo nome, chamadas User, cada uma em um namespace diferente:

Arquivo UserBlog.php, namespace Blog:
<?php
namespace Blog;

class User {
   private $name;

   public function setName ($username) {
     $this->name = $username;
   }

   public function getName() {
     return "The username in Blog is " . $this->name;
   }

}

Arquivo UserCms.php, namespace Cms:
<?php
namespace Cms;

class User {
   private $name;

   public function setName ($username) {
     $this->name = $username;
   }

   public function getName() {
     return "The username in CMS is " . $this->name;
   }

}

Usando Namespaces

É possível referenciar os elementos de uma namespace em até 3 maneiras diferentes:

  • Nome não qualificado. Exemplo de uma chamada de nome não qualificado: $a = new User(); Se a namespace corrente do arquivo for “Blog”, namespace Blog; , a declaração anterior será transformada para Blog\User();. Caso o código for global, ou seja, código sem namespace, será transformada para simplesmente User();
  • Nome qualificado. São chamadas utilizando nomes relativos, quando usa-se sub-namespaces. Exemplo: namespace Company\Blog;. A seguinte declaração instancia a classe User utilizando “Nome Qualificado”: $a = new Blog\User();. Como a namespace raiz do arquivo é “Company”, a declaração anterior será transformada para Company\Blog\User();. Vamos ver a utilização de sub-namespaces mais adiante.
  • Full Qualified Name. São chamadas utilizando nomes absolutos. Exemplo: $a = new \Blog\User(); $b = new \Cms\User(); $c = new \Company\Blog\User();

Vamos criar um novo arquivo para exemplificar a utilização de namespaces:

Arquivo TestNamespace.php:
<?php
// incluir as classes com mesmo nome, porém com diferentes namespaces.
require_once("UserBlog.php");
require_once("UserCms.php");

// Instanciar class User do namespace Blog. Usando full qualified name.
$user = new \Blog\User();
$user->setName("Douglas");
print $user->getName();

print PHP_EOL;

// Instanciar class User do namespace Cms. Usando full qualified name.
$user2 = new \Cms\User();
$user2->setName("Douglas");
print $user2->getName();

A saída do script acima:

The username in Blog is Douglas
The username in CMS is Douglas

Nome não-qualificado

No exemplo anterior instanciamos as classes User de diferentes namespaces usando o full-qualified-name. Para ilustrar a chamada de uma classe usando nome não-qualificado vamos definir a namespace do arquivo TestNamespace.php para “BLog”:

namespace Blog;

Desta maneira temos o arquivo TesteNamespace.php na mesma namespace que a classe User do Arquivo UserBlog.php. Portanto no lugar de usar “\Blog\User();” podemos simplesmente usar:

$user = new User();

Para instanciar a classe User do namespace Cms, continuamos a ter que usar o full-qualified-name.

Sub-namespaces

Semelhantes à diretórios e arquivos, namespaces em php podem ser declaradas em forma de hierarquia. Exemplo:
namespace Project\Blog;

Nome Qualificado

Para exemplificar a chamada de uma classe usando nome qualificado vamos definir sub-namespaces em nossos 3 arquivos:

Troque a linha que define a namespace para cada um dos arquivos:

UserBlog.php
namespace Project\Blog;

UserCms.php
namespace Project\Cms;

TesteNamespace.php
namespace Project;

Como todos os arquivos tem definido o namespace raiz para Project, podemos usar “nome-qualificado”, ou nome relativo, para acessar as classes dentro do arquivo TesteNamespace.php:

$user = new Blog\User(); // transformado para \Project\Blog\User();
...
$user1 = new Cms\User(); // transformado para \Project\Cms\User();

Automaticamente $user = new Blog\User() vai ser transformado para $user = new \Project\Blog\User(); e $user1 = new Cms\User(); vai ser resolvido para $user1 = new \Project\Cms\User(); de forma transparente.

Importing e Aliasing

A opção de referenciar um elemento utilizando um nome mais curto, ou alias, é uma importante característica de namespaces.

A palavra chave use é utilizada para importing/aliasing.

Vamos alterar nosso arquivo TesteNamespace.php para exemplificar a utilização de importing/aliasing.

TesteNamespace.php:
namespace Project;
use Project\Blog\User as BlogUser;
use Project\Cms\User; // É o mesmo que utilizar "use Project\Cms\User as User;"
...
$user = new BlogUser(); // Instancia o objeto da classe Project\Blog\User
...
$user2 = new User(); // Instancia o objeto da classe Project\Cms\User

Obs: Nomes full qualified são absolutos e não são afectados por imports.

Global Space

Sem a definição de namespace, todas as classes e funções pertencem ao espaço global . Funciona da mesma maneira que as antigas versões do php onde ainda não existiam namespaces.

Vamos criar uma nova classe User, desta vez pertencendo ao espaço global. Perceba que não definimos nenhuma namespace. Isto significa que a classe pertence ao espaço global.

Arquivo User.php, “global space”:
<?php
class User {
   private $name;

   public function setName ($username) {
     $this->name = $username;
   }

   public function getName() {
     return "The username in Global is " . $this->name;
   }

}

Para chamarmos um nome que esta no espaço global, devemos colocar o prefixo “\” no nome, ou simplesmente chamar o nome diretamente caso não exista nomes iguais no namespace corrente.

Vamos alterar mais uma vez o arquivo TesteNamespace.php onde vamos adicionar a chamada para a classe User que esta no espaço global.

TesteNamespace.php:
...
require_once("User.php"); // incluir classe global
...
print PHP_EOL;
$user3 = new \User(); // chamando a classe "User" no espaço global.
$user3->setName("Douglas");
print $user3->getName();
...

A nova saída após a execução do arquivo TesteNamespace.php:
The username in Blog is Douglas
The username in CMS is Douglas
The username in Global is Douglas

Funções e constantes

Além das classes, namespaces podem ser usadas em funções e constantes.

<?php
namespace A\B\C;
const TESTCONST = true;


function fopen() { // função em A\B\C\fopen
  $f = \fopen(...); // espaço global
  return TESTCONST; // constante em A\B\C\TESTECONST
}

A constante __NAMESPACE__

O valor da constante __NAMESPACE__ é uma string com o valor da namespace corrente. Em um código sem namespace, espaço global, o valor da constante é um string vazia.

A palavra chave “namespace” também pode ser usada para requisitar um elemento referente a namespace corrente.

<?php
namespace Foo\Bar;

echo __NAMESPACE__; // exibe Foo\Bar
namespace\func(); // chama a função em Foo\Bar\func();

Multiplos namespaces em um mesmo arquivo

PHP permite que você defina mais de uma namespace em um mesmo arquivo. É possível mesclar código sem namespace com código com namespace. Ao utilizar mais de uma namespace em um mesmo arquivo é fortemente recomendável o uso de chaves “{“. Exemplo:


namespace Projeto\Secao1 {
// código inserido arqui estará no namespace Projeto\Secao1
    const USER_STATE = 1;
    function get_user_state() { ... }
    class UserState() { ... }
}

namespace Projeto\Secao2 {
// código inserido arqui estará no namespace Projeto\Secao2
    const USER_STATE = 1;
    function get_user_state() { ... }
    class UserState() { ... }
}

namespace {
// código inserido arqui estará no espaço global.
    const USER_STATE = 1;
    function get_user_state() { ... }
    class UserState() { ... }
}

Make a Comment

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

Liked it here?
Why not try sites on the blogroll...

%d blogueiros gostam disto: