Perguntas Frequentes: Coisas que você precisa saber sobre namespaces
(PHP 5 >= 5.3.0, PHP 7, PHP 8)
Estas perguntas frequentes são divididas em duas seções: perguntas comuns e alguns detalhes de implementação úteis para entender os pormenores.
Primeiro, as perguntas comuns.
- Se não usar namespaces, devo me importar com esta documentação?
- Como usar classes internas ou globais em um namespace?
- Como usar classes, funções ou constantes de namespace em seu próprio namespace?
-
Como nomes como
\meu\nome
ou\nome
são resolvidos? -
Como um nome como
meu\nome
é resolvido? -
Como um nome de classe não qualificado
como
nome
é resolvido? -
Como um nome de função
não qualificado ou nome de constante não qualificado
como
nome
é resolvido?
Há alguns detalhes de implementação dos namespaces úteis para entendê-los melhor.
- Nomes de importação não devem entrar em conflito com classes definidas no mesmo arquivo
- Namespaces aninhados não são permitidos.
- Nomes de namespace dinâmicos (identificadores entre aspas) devem escapar a barra invertida
- Constantes indefinidas referenciadas usando qualquer barra invertida geram erro fatal
-
Não é possível substituir
as constantes especiais
null
,true
oufalse
Se não usar namespaces, devo me importar com esta documentação?
Não. Namespaces não afetam nenhum código existente de forma alguma, ou qualquer código ainda a ser escrito que não contenha namespaces. Você pode escrever este código se desejar:
Example #1 Acessando classes globais fora de um namespace
<?php
$a = new \stdClass;
?>
O exemplo acima é equivalente ao seguinte código:
Example #2 Acessando classes globais fora de um namespace
<?php
$a = new stdClass;
?>
Como usar classes internas ou globais em um namespace?
Example #3 Acessando classes internas em namespaces
<?php
namespace foo;
$a = new \stdClass;
function test(\ArrayObject $exemplo_com_tipo_de_parametro = null) {}
$a = \DirectoryIterator::CURRENT_AS_FILEINFO;
// estendendo uma classe interna ou global
class MinhaExcecao extends \Exception {}
?>
Como usar classes, funções ou constantes de namespace em seu próprio namespace?
Example #4 Acessando classes, funções ou constantes internas em namespaces
<?php
namespace foo;
class MinhaClasse {}
// usando uma classe do namespace atual como tipo de parâmetro
function test(MinhaClasse $exemplo_com_tipo_de_parametro = null) {}
// outra forma de usar a classe do namespace atual como tipo de parâmetro
function test(\foo\MinhaClasse $exemplo_com_tipo_de_parametro = null) {}
// estendendo uma classe do namespace atual
class Estendida extends MinhaClasse {}
// acessando uma função global
$a = \funcao_global();
// acessando uma constante global
$b = \INI_ALL;
?>
Como nomes como \meu\nome
ou \nome
são resolvidos?
Nomes que começam com uma barra invertida (\
) sempre são resolvidos
para seu conteúdo exato, então \meu\nome
é o mesmo que meu\nome
e \Exception
é o mesmo que Exception
.
Example #5 Nomes totalmente qualificados
<?php
namespace foo;
$a = new \meu\nome(); // instancia um objeto da classe "meu\nome"
echo \strlen('olá'); // invoca a função "strlen"
$a = \INI_ALL; // define $a com o valor da constante "INI_ALL"
?>
Como um nome como meu\nome
é resolvido?
Nomes que contêm barra invertida, mas não começam com uma barra invertida, como
meu\nome
podem ser resolvidos de duas maneiras diferentes.
Se houver
uma instrução de importação que cria o apelido meu
para outro nome, então
o apelido da importação será aplicado ao meu
em meu\nome
.
Caso contrário, o nome do namespace atual será prefixado a meu\nome
.
Example #6 Nomes qualificados
<?php
namespace foo;
use bla\bla as foo;
$a = new meu\nome(); // instancia um objeto da classe "foo\meu\nome"
foo\bar::nome(); // chama o método estático "nome" na classe "bla\bla\bar"
minha\bar(); // chama a função "foo\minha\bar"
$a = minha\BAR; // define $a com o valor da constante "foo\minha\BAR"
?>
Como um nome de classe não qualificado como nome
é resolvido?
Nomes de classes que não contêm barra invertida como
nome
podem ser resolvidos de duas maneiras diferentes.
Se houver
uma instrução de importação que cria o apelido nome
para outro nome, então
o apelido da importação será aplicado.
Caso contrário, o nome do namespace atual será prefixado a nome
.
Example #7 Nomes de classe não qualificados
<?php
namespace foo;
use bla\bla as foo;
$a = new nome(); // instancia um objeto da classe "foo\nome"
foo::nome(); // chama o método estático "nome" na classe "bla\bla"
?>
Como um nome de função não qualificado ou nome de constante não qualificado
como nome
é resolvido?
Nomes de funções ou constantes que não contêm barra invertida como
nome
podem ser resolvidos de duas maneiras diferentes.
Primeiro, o nome do namespace atual será prefixado a nome
.
Finalmente, se a contante ou função nome
não existir
no namespace atual, uma constante ou função global nome
será usada se existir.
Example #8 Nomes de funções ou constantes não qualificados
<?php
namespace foo;
use bla\bla as foo;
const FOO = 1;
function minha() {}
function foo() {}
function sort(&$a)
{
\sort($a); // chama a função global "sort"
$a = array_flip($a);
return $a;
}
minha(); // chama "foo\minha"
$a = strlen('hi'); // chama a função global "strlen" porque não existe "foo\strlen"
$arr = array(1,3,2);
$b = sort($arr); // chama a função "foo\sort"
$c = foo(); // chama a função "foo\foo" - a importação não é aplicada
$a = FOO; // define $a com o valor da constante "foo\FOO" - a importação não é aplicada
$b = INI_ALL; // define $b com o valor da constante global "INI_ALL"
?>
Nomes de importação não devem entrar em conflito com classes definidas no mesmo arquivo
As seguintes combinações de script são válidas:
arquivo1.php
<?php
namespace minha\coisa;
class MinhaClasse {}
?>
outra.php
<?php
namespace outra;
class coisa {}
?>
arquivo2.php
<?php
namespace minha\coisa;
include 'arquivo1.php';
include 'outra.php';
use outra\coisa as MinhaClasse;
$a = new MinhaClasse; // instancia um objeto da classe coisa do namespace outra
?>
Não há conflito de nomes, mesmo que a classe MinhaClasse
exista
dentro do namespace minha\coisa
, porque a definição de MinhaClasse está
em um arquivo separado. No entanto, o próximo exemplo causa um erro fatal de conflito de nomes
porque MinhaClasse está definida no mesmo arquivo que a declaração use.
<?php
namespace minha\coisa;
use outra\coisa as MinhaClasse;
class MinhaClasse {} // erro fatal: MinhaClasse está em conflito com a declaração de importação
$a = new MinhaClasse;
?>
Namespaces aninhados não são permitidos
O PHP não permite aninhar namespaces.
<?php
namespace minha\coisa {
namespace aninhada {
class foo {}
}
}
?>
<?php
namespace minha\coisa\aninhada {
class foo {}
}
?>
Nomes de namespace dinâmicos (identificadores entre aspas) devem escapar a barra invertida
É muito importante perceber que, como a barra invertida é usada como um caractere de escape dentro de strings, ela sempre deve ser duplicada quando usada em uma string. Caso contrário, existe o risco de consequências não desejadas:
Example #9 Perigos do uso de nomes com namespace em uma string com aspas duplas
<?php
$a = "\nome\perigoso"; // \n é uma nova linha dentro de strings com aspas duplas!
$obj = new $a;
$a = 'nada\perigoso'; // não há problemas aqui.
$obj = new $a;
?>
Constantes indefinidas referenciadas usando qualquer barra invertida geram erro fatal
Qualquer constante indefinida não qualificada como FOO
gerará
um alerta explicando que o PHP assumiu que FOO
era o valor
da constante. Qualquer constante, qualificada ou totalmente qualificada, que contenha
uma barra invertida produzirá um erro fatal se não for encontrada.
Example #10 Constantes não definidas
<?php
namespace bar;
$a = FOO; // Produz um alerta - constante indefinida FOO assumiu "FOO"
$a = \FOO; // Erro fatal, constante de namespace indefinida FOO
$a = Bar\FOO; // Erro fatal, constante de namespace indefinida bar\Bar\FOO
$a = \Bar\FOO; // Erro fatal, constante de namespace indefinida Bar\FOO
?>
Não é possível substituir as constantes especiais null
, true
ou false
Qualquer tentativa de definir uma constante de namespace que seja uma constante especial nativa resultará em um erro fatal.
Example #11 Constantes não definidas
<?php
namespace bar;
const NULL = 0; // Erro fatal
const true = 'verdadeiro'; // Também um erro fatal
// etc.
?>