Namespace PHP (namespace) foi adicionado no PHP 5.3. Se você estudou C# e Java, namespace não é novidade. No entanto, ainda tem um significado muito importante no PHP.
Namespaces PHP podem resolver os dois tipos de problemas a seguir:
Conflitos de nomes entre o código escrito pelo usuário e classes/funções/constantes internas do PHP ou classes/funções/constantes de terceiros.
Crie um nome alternativo (ou curto) para um nome identificador muito longo (geralmente definido para aliviar o primeiro tipo de problema) para melhorar a legibilidade do código-fonte.
Por padrão, todos os nomes de constantes, classes e funções são colocados no espaço global, assim como antes dos namespaces suportados pelo PHP.
Namespaces são declarados usando a palavra-chave namespace. Se um arquivo contiver um namespace, ele deverá declarar o namespace antes de todos os outros códigos. O formato da sintaxe é o seguinte;
<?php // Defina o código no namespace 'MyProject' namespace MyProject; // ... código...
Você também pode definir diferentes códigos de namespace no mesmo arquivo, como:
<?php namespace MyProject;const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ }namespace AnotherProject;const CONNECT_OK = 1;class Connection { /* .. . */ }função conectar() { /* ... */ }?>
Não é recomendado usar esta sintaxe para definir vários namespaces em um único arquivo. Recomenda-se usar a seguinte forma de sintaxe entre colchetes.
<?phpnamespace MeuProjeto { const CONNECT_OK = 1; class Conexão { /* ... */ } function connect() { /* ... */ }}namespace OutroProjeto { const CONNECT_OK = 1; . */ } função conectar() { /* ... */ }}?>
Para combinar código global não-namespace com código de namespace, apenas a sintaxe de colchetes pode ser usada. O código global deve ser colocado entre uma instrução de namespace sem nome seguida de colchetes, por exemplo:
<?phpnamespace MeuProjeto {const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ }}namespace { // Código global session_start();$a = MyProject connect();echo MeuProjetoConnection::start();}?>
O único código legal antes de declarar um namespace é a instrução declare que define a codificação do arquivo de origem. Todo código não-PHP, incluindo espaços em branco, não pode aparecer antes de uma declaração de namespace.
<?phpdeclare(encoding='UTF-8'); //Defina vários namespaces e namespaces de código não incluídos no namespace MyProject {const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { / * ... */ }}namespace { // Código global session_start();$a = MyProjectconnect();echo MyProjectConnection::start();}?>
O código a seguir causará um erro de sintaxe:
<html><?phpnamespace MyProject; // "<html>" aparecer antes do namespace causará um erro fatal - o namespace deve ser a primeira instrução do script do programa?>
Assim como o relacionamento entre diretórios e arquivos, os namespaces PHP também permitem especificar nomes hierárquicos de namespaces. Portanto, os nomes dos namespaces podem ser definidos de maneira hierárquica:
<?phpnamespace MyProjectSubLevel; //Declarar um namespace único hierárquico const CONNECT_OK = 1;class Connection { /* ... */ }function Connect() { /* ... */ }?>
O exemplo acima cria a constante MyProjectSubLevelCONNECT_OK, a classe MyProjectSubLevelConnection e a função MyProjectSubLevelConnect.
Os nomes de classes no namespace PHP podem ser referenciados de três maneiras:
Um nome não qualificado ou um nome de classe sem prefixo, como $a=new foo() ou foo::staticmethod();. Se o namespace atual for currentnamespace, foo será resolvido para currentnamespacefoo. Se o código que usa foo for global e não contiver código em nenhum namespace, então foo será resolvido como foo. Aviso: Se uma função ou constante em um namespace for indefinida, a função ou nome de constante não qualificado será resolvido para uma função global ou nome de constante.
Um nome qualificado ou um nome que inclua um prefixo, como $a = new subnamespacefoo(); ou subnamespacefoo::staticmethod();. Se o namespace atual for currentnamespace, foo será resolvido para currentnamespacesubnamespacefoo. Se o código que usa foo for global, código não contido em nenhum namespace, foo será resolvido para subnamespacefoo.
Um nome totalmente qualificado ou um nome que inclua um operador de prefixo global, por exemplo, $a = new currentnamespacefoo(); ou currentnamespacefoo::staticmethod();. Nesse caso, foo é sempre resolvido para o nome literal currentnamespacefoo no código.
Aqui está um exemplo de uso desses três métodos:
código do arquivo arquivo1.php
<?phpnamespace FooBarsubnamespace; const FOO = 1;function foo() {}class foo{ função estática staticmethod() {}}?>
código do arquivo file2.php
<?phpnamespace FooBar;include 'file1.php';const FOO = 2;function foo() {}class foo{ static function staticmethod() {}}/* Nome não qualificado*/foo(); é a função FooBarfoofoo::staticmethod() // Ela é analisada na classe FooBarfoo e o método é staticmethodecho FOO; Resolve para a constante FooBarFOO/* nome qualificado*/subnamespacefoo(); // Resolve para a função FooBarsubnamespacefoosubnamespacefoo::staticmethod(); foo, // e métodos de classe staticmethodecho subnamespaceFOO; // analisados para constante FooBarsubnamespaceFOO /* Nome totalmente qualificado */FooBarfoo(); // Resolve para a função FooBarfooFooBarfoo::staticmethod(); Método staticmethodecho FooBarFOO; //Resolvido como constante FooBarFOO?>
Observe que para acessar qualquer classe, função ou constante global, você pode usar um nome totalmente qualificado, como strlen() ou Exception ou INI_ALL.
Acesse classes, funções e constantes globais dentro de um namespace:
<?phpnamespace Foo;function strlen() {}const INI_ALL = 3;class Exception {}$a = strlen('hi'); // Chama a função global strlen$b = INI_ALL$; c = new Exception('error'); // Instancia a classe global Exception?>
A implementação de namespaces PHP é afetada pela natureza dinâmica da própria linguagem. Então se você quiser converter o código abaixo em um namespace, acesse os elementos dinamicamente.
código do arquivo exemplo1.php:
<?phpclass classname{ function __construct() { echo __METHOD__,"n"; }}function funcname(){ echo __FUNCTION__,"n";}const constname = "global";$a = 'classname';$obj = new $a; // imprime classname::__construct$b = 'funcname';$b(); constante('constname'), "n"; // imprime global?>
Você deve usar um nome completo (o nome da classe incluindo o prefixo do namespace). Observe que a barra invertida inicial é desnecessária porque não há diferença entre nomes qualificados e totalmente qualificados em nomes de classes dinâmicas, nomes de funções ou nomes de constantes.
Acessar dinamicamente elementos de um namespace
<?phpnamespace namespacename;class classname{ function __construct() { echo __METHOD__,"n";}function funcname(){ echo __FUNCTION__,"n";}const constname = "namespaced";include 'example1.php' ;$a = 'classname';$obj = new $a; // Saída classname::__construct$b = 'funcname';$b(); // Nome da função de saída echo constante('constname'), "n"; // Saída global/* Se aspas duplas forem usadas, o método de uso é "\namespacename\classname "* /$a = 'namespacenameclassname';$obj = new $a; // Saída namespacenameclassname::__construct$a = 'namespacenameclassname';$obj = new $a; // Saída namespacenameclassname::__construct$b = 'namespacenamefuncname';$b(); // Saída namespacenamefuncnameecho constante( 'namespacenameconstname'), "n"; // Saída namespacedecho constante('namespacenameconstname'), "n"; Saída com namespace?>
PHP suporta dois métodos abstratos de acesso a elementos dentro do namespace atual, a constante mágica __NAMESPACE__ e a palavra-chave namespace.
O valor da constante __NAMESPACE__ é uma string contendo o nome do namespace atual. No código global, não incluído em nenhum namespace, contém uma string vazia.
Exemplo __NAMESPACE__, código em um namespace
<?phpnamespace MeuProjeto;echo '"', __NAMESPACE__, '"' // Saída "MeuProjeto"?>
Exemplo __NAMESPACE__, código global
<?phpecho '"', __NAMESPACE__, '"' // Saída ""?>
A constante __NAMESPACE__ é útil ao criar nomes dinamicamente, por exemplo:
Crie nomes dinamicamente usando __NAMESPACE__
<?phpnamespace MeuProjeto;function get($classname){ $a = __NAMESPACE__ '\' .
A palavra-chave namespace pode ser usada para acessar explicitamente elementos no namespace ou subnamespaces atuais. É equivalente ao operador self nas classes.
operador de namespace, código no namespace
<?phpnamespace MyProject;use blahblah como meu; // veja "Usando namespaces: importando/aliasing"blahmine(); // chama a função blahblahmine()namespaceblahmine(); chama a função MyProjectblahmine()namespacefunc(); // chama a função MyProjectfunc()namespacesubfunc(); MyProjectsubfunc()namespacecname::method(); // chama o método estático "método" da classe MyProjectcname$a = new namespacesubcname(); // instancia o objeto da classe MyProjectsub; cname$b = namespaceCONSTANT; // atribui o valor da constante MyProjectCONSTANT a $b?>
operador de namespace, código global
<?phpnamespacefunc(); // chama a função func()namespacesubfunc(); // chama a função subfunc()namespacecname::method(); class cname$a = new namespacesubcname(); // instancia o objeto da classe subcname$b = namespaceCONSTANT; // atribui o valor da constante CONSTANT a $b?>
O suporte a namespaces PHP tem duas maneiras de usar aliases ou importações: usando aliases para nomes de classes ou usando aliases para nomes de namespaces.
Em PHP, o alias é implementado através do operador use. Aqui está um exemplo usando todos os três métodos de importação possíveis:
1. Use o operador use para importar/usar aliases
<?phpnamespace foo;use MyFullClassname as Another;// O exemplo a seguir é o mesmo que use MyFullNSname como NSname use MyFullNSname;// Importe uma classe global use ArrayObject;$obj = new namespaceAnother; // Instancia o objeto fooAnother $obj = new Another; // Instancia o objeto MyFullClassname NSnamesubnsfunc(); Chame a função MyFullNSnamesubnsfunc$a = new ArrayObject(array(1)); // Instancie o objeto ArrayObject // Se você não usar "use ArrayObject", instancie um objeto fooArrayObject? >
2. Uma linha contém várias instruções de uso
<?phpuse MyFullClassname as Another, MyFullNSname;$obj = new Another; // Instancia o objeto MyFullClassname NSnamesubnsfunc(); subnsfunc?>
As operações de importação são executadas durante a compilação, mas nomes de classes dinâmicas, nomes de funções ou nomes de constantes não.
3. Importação e nomes dinâmicos
<?phpuse MyFullClassname as Another, MyFullNSname;$obj = new Another; // Instancia um objeto MyFullClassname $a = 'Another';$obj = new $a; um Outro objeto?>
Além disso, a operação de importação afeta somente nomes qualificados e não qualificados. Os nomes totalmente qualificados não são afetados pelas importações porque são determinísticos.
4. Importação e nomes totalmente qualificados
<?phpuse MyFullClassname as Another, MyFullNSname;$obj = new Another; // Instancia MyFullClassname class $obj = new Another; thing; // Instanciar MyFullClassnamething class $obj = new Anotherthing; // Instanciar Anotherthing class?>
Dentro de um namespace, quando o PHP encontra uma classe, função ou nome de constante não qualificado, ele usa uma estratégia de precedência diferente para resolver o nome. Os nomes das classes sempre são resolvidos para nomes no namespace atual. Portanto ao acessar nomes de classes que são internos ao sistema ou não contidos no namespace, deve-se utilizar o nome completo, por exemplo:
1. Acesse classes globais no namespace
<?phpnamespace ABC;class Exception estende Exception {}$a = new Exception('hi'); // $a é um objeto da classe ABCException $b = new Exception( 'hi'); // $b é um objeto da classe Exception $c = new ArrayObject; // Erro fatal, classe ABCArrayObject não encontrada?>
Para funções e constantes, se a função ou constante não existir no namespace atual, o PHP voltará a usar a função ou constante no espaço global.
2. Faça backup de funções/constantes globais no namespace
<?phpnamespace ABC;const E_ERROR = 45;function strlen($str){ return strlen($str) - 1;}echo E_ERROR, "n" // Saída "45"echo INI_ALL, " n"; // Saída "7" - usa constante global INI_ALLecho strlen('hi'), "n"; // Saída "2"if (is_array('hi')) { // Saída "não é array" echo "é arrayn";} else { echo "não é arrayn";}?>
Se nenhum namespace for definido, todas as classes e funções serão definidas no espaço global, assim como antes do PHP introduzir o conceito de namespace. Prefixar um nome com indica que o nome está no espaço global, mesmo que esteja em outro namespace.
Use instruções de espaço global
<?phpnamespace ABC;/* Esta função é ABCfopen */function fopen() { /* ... */ $f = fopen(...); A função fopen retorna $f;} ?>
Desde a introdução dos namespaces, a coisa mais propensa a erros é ao usar uma classe, qual é o caminho de busca para esta classe.
<?phpnamespace A;use BD, CE as F;// Chamada de função foo() // Primeiro tente chamar a função foo() definida no namespace "A" // Depois tente chamar o global function" foo"foo(); // Chame a função de espaço global "foo" myfoo() // Chame a função "foo" definida no namespace "Amy" F(); Primeiro tente chamar a função "F" definida no namespace "A" // Depois tente chamar a função global "F" // Referência de classe new B(); // Cria a classe "B" definida no namespace "A" Um objeto de class "AB" new D(); // Se não for encontrado, tente carregar automaticamente a classe "AB" new D(); // Usando regras de importação, crie um objeto da classe "D" definido no namespace "B"; " // Se não encontrado Se encontrado, tenta carregar automaticamente a classe "BD" new F(); // Usando regras de importação, cria um objeto da classe "E" definido no namespace "C" // Se não for encontrado, tenta carregar automaticamente a classe "CE" new B(); da classe "B" definida no espaço global // Se não for encontrado, tente carregar automaticamente a classe "B" new D(); // Crie um objeto da classe "D" definido no espaço global // Se não for encontrado, tente classe de carregamento automático "D" novo F(); // Cria um objeto da classe "F" definido no espaço global // Se não for encontrado, tenta carregar automaticamente a classe "F" // Chama um método estático ou função de namespace em outro namespace Bfoo(); ; // Chama a função "foo" no namespace "AB" B::foo(); // Chama o método "foo" da classe "B" definido no namespace "A" // Se a classe "AB" for não encontrado , então tente carregar automaticamente a classe "AB" D::foo(); // Use regras de importação para chamar o método "foo" da classe "D" definido no namespace "B" // If class "BD" " " Se não for encontrado, tente carregar automaticamente a classe "BD"Bfoo(); // Chame a função "foo" no namespace "B" B::foo(); função no espaço global Classe "B" O método "foo" // Se a classe "B" não for encontrada, tente carregar automaticamente a classe "B" // Um método ou função estática no namespace atual AB::foo(); // Chama o namespace "A"; método "foo" da classe "B" definido em A" // Se a classe "AAB" não for encontrada, tente carregar automaticamente a classe "AAB"AB::foo() ; // Chame o método "foo" da classe "B" definido no namespace "A" // Se a classe "AB" não for encontrada, tente carregar automaticamente a classe "AB"?>
A resolução de nomes segue as seguintes regras:
Chamadas para nomes totalmente qualificados de funções, classes e constantes são resolvidas em tempo de compilação. Por exemplo, new AB resolve para a classe AB .
Todos os nomes não qualificados e nomes qualificados (nomes não totalmente qualificados) são convertidos em tempo de compilação de acordo com as regras de importação atuais. Por exemplo, se o namespace ABC fosse importado como C , as chamadas para CDe() seriam traduzidas para ABCDe() .
Dentro de um namespace, todos os nomes qualificados que não forem convertidos de acordo com as regras de importação terão o nome do namespace atual anexado a eles. Por exemplo, se CDe() for chamado no namespace AB , CDe() será convertido em ABCDe() .
Nomes de classes não qualificados são convertidos em tempo de compilação de acordo com as regras de importação atuais (nomes completos são usados em vez de nomes abreviados de importação). Por exemplo, se o namespace ABC for importado como C, new C() será convertido em new ABC() .
Dentro de um namespace (por exemplo, AB), as chamadas de função para nomes não qualificados são resolvidas em tempo de execução. Por exemplo, uma chamada para a função foo() é analisada assim:
Encontre uma função chamada ABfoo() no namespace atual
Tente encontrar e chamar a função foo() no espaço global .
Chamadas para nomes não qualificados ou classes de nomes qualificados (nomes não totalmente qualificados) dentro de um namespace (por exemplo, AB ) são resolvidas em tempo de execução. A seguir está o processo de análise de chamada de new C() e new DE() : Análise de new C() :
Encontre as classes ABC no namespace atual.
Tente carregar automaticamente as classes ABC .
Análise de novo DE() :Anexe o nome da classe ao nome do namespace atual para se tornar: ABDE e procure por essa classe.
Tente carregar automaticamente a classe ABDE .
Para fazer referência a uma classe global no namespace global, o nome totalmente qualificado new C() deve ser usado.