PHP 5.3 parte I: Namespaces

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 BlogUser();. 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 CompanyBlog;. A seguinte declaração instancia a classe User utilizando “Nome Qualificado”: $a = new BlogUser();. Como a namespace raiz do arquivo é “Company”, a declaração anterior será transformada para CompanyBlogUser();. Vamos ver a utilização de sub-namespaces mais adiante.
  • Full Qualified Name. São chamadas utilizando nomes absolutos. Exemplo: $a = new BlogUser(); $b = new CmsUser(); $c = new CompanyBlogUser();

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 BlogUser();
$user->setName("Douglas");
print $user->getName();

print PHP_EOL;

// Instanciar class User do namespace Cms. Usando full qualified name.
$user2 = new CmsUser();
$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 “BlogUser();” 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 ProjectBlog;

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 ProjectBlog;

UserCms.php
namespace ProjectCms;

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 BlogUser(); // transformado para ProjectBlogUser();
...
$user1 = new CmsUser(); // transformado para ProjectCmsUser();

Automaticamente $user = new BlogUser() vai ser transformado para $user = new ProjectBlogUser(); e $user1 = new CmsUser(); vai ser resolvido para $user1 = new ProjectCmsUser(); 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 ProjectBlogUser as BlogUser;
use ProjectCmsUser; // É o mesmo que utilizar "use ProjectCmsUser as User;"
...
$user = new BlogUser(); // Instancia o objeto da classe ProjectBlogUser
...
$user2 = new User(); // Instancia o objeto da classe ProjectCmsUser

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 ABC;
const TESTCONST = true;


function fopen() { // função em ABCfopen
  $f = fopen(...); // espaço global
  return TESTCONST; // constante em ABCTESTECONST
}

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 FooBar;

echo __NAMESPACE__; // exibe FooBar
namespacefunc(); // chama a função em FooBarfunc();

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 ProjetoSecao1 {
// código inserido arqui estará no namespace ProjetoSecao1
    const USER_STATE = 1;
    function get_user_state() { ... }
    class UserState() { ... }
}

namespace ProjetoSecao2 {
// código inserido arqui estará no namespace ProjetoSecao2
    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() { ... }
}

Please follow and like us:

Follow

Get every new post on this blog delivered to your Inbox.

Join other followers: