CakeFest 2024: The Official CakePHP Conference

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.

  1. Se não usar namespaces, devo me importar com esta documentação?
  2. Como usar classes internas ou globais em um namespace?
  3. Como usar classes, funções ou constantes de namespace em seu próprio namespace?
  4. Como nomes como \meu\nome ou \nome são resolvidos?
  5. Como um nome como meu\nome é resolvido?
  6. Como um nome de classe não qualificado como nome é resolvido?
  7. 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.

  1. Nomes de importação não devem entrar em conflito com classes definidas no mesmo arquivo
  2. Namespaces aninhados não são permitidos.
  3. Nomes de namespace dinâmicos (identificadores entre aspas) devem escapar a barra invertida
  4. Constantes indefinidas referenciadas usando qualquer barra invertida geram erro fatal
  5. Não é possível substituir as constantes especiais null, true ou false

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:

Exemplo #1 Acessando classes globais fora de um namespace

<?php
$a
= new \stdClass;
?>

O exemplo acima é equivalente ao seguinte código:

Exemplo #2 Acessando classes globais fora de um namespace

<?php
$a
= new stdClass;
?>

Como usar classes internas ou globais em um namespace?

Exemplo #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?

Exemplo #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.

Exemplo #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.

Exemplo #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.

Exemplo #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.

Exemplo #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 {}
}
}
?>
No entanto, é fácil simular namespaces aninhados da seguinte forma:
<?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:

Exemplo #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;
?>
Dentro de uma string com aspas simples, a sequência de escape da barra invertida é muito mais segura de usar, mas ainda é uma prática recomendada escapar as barras invertidas em todas as strings.

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.

Exemplo #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.

Exemplo #11 Constantes não definidas

<?php
namespace bar;
const
NULL = 0; // Erro fatal
const true = 'verdadeiro'; // Também um erro fatal
// etc.
?>

add a note

User Contributed Notes 6 notes

up
15
manolachef at gmail dot com
11 years ago
There is a way to define a namespaced constant that is a special, built-in constant, using define function and setting the third parameter case_insensitive to false:

<?php
namespace foo;
define(__NAMESPACE__ . '\NULL', 10); // defines the constant NULL in the current namespace
var_dump(NULL); // will show 10
var_dump(null); // will show NULL
?>

No need to specify the namespace in your call to define(), like it happens usually
<?php
namespace foo;
define(INI_ALL, 'bar'); // produces notice - Constant INI_ALL already defined. But:

define(__NAMESPACE__ . '\INI_ALL', 'bar'); // defines the constant INI_ALL in the current namespace
var_dump(INI_ALL); // will show string(3)"bar". Nothing unespected so far. But:

define('NULL', 10); // defines the constant NULL in the current namespace...
var_dump(NULL); // will show 10
var_dump(null); // will show NULL
?>

If the parameter case_insensitive is set to true
<?php
namespace foo;
define (__NAMESPACE__ . '\NULL', 10, true); // produces notice - Constant null already defined
?>
up
7
shaun at slickdesign dot com dot au
7 years ago
When creating classes or calling static methods from within namespaces using variables, you need to keep in mind that they require the full namespace in order for the appropriate class to be used; you CANNOT use an alias or short name, even if it is called within the same namespace. Neglecting to take this into account can cause your code to use the wrong class, throw a fatal missing class exception, or throw errors or warnings.

In these cases, you can use the magic constant __NAMESPACE__, or specify the full namespace and class name directly. The function class_exists also requires the full namespace and class name, and can be used to ensure that a fatal error won't be thrown due to missing classes.

<?php

namespace Foo;
class
Bar {
public static function
test() {
return
get_called_class();
}
}

namespace
Foo\Foo;
class
Bar extends \Foo\Bar {
}

var_dump( Bar::test() ); // string(11) "Foo\Foo\Bar"

$bar = 'Foo\Bar';
var_dump( $bar::test() ); // string(7) "Foo\Bar"

$bar = __NAMESPACE__ . '\Bar';
var_dump( $bar::test() ); // string(11) "Foo\Foo\Bar"

$bar = 'Bar';
var_dump( $bar::test() ); // FATAL ERROR: Class 'Bar' not found or Incorrect class \Bar used
up
3
teohad at NOSPAM dot gmail dot com
7 years ago
[Editor's note: that behavior is caused by a bug in PHP 7.0, which has been fixed as of PHP 7.0.7.]

Regarding the entry "Import names cannot conflict with classes defined in the same file".
- I found that since PHP 7.0 this is no longer the case.
In PHP 7.0 you can have a class with a name that matches an imported class (or namespace or both at the same time).

<?php
namespace ns1 {
class
ns1 {
public static function
write() {
echo
"ns1\\ns1::write()\n";
}
}
}

namespace
ns1\ns1 {
class
ns1c {
public static function
write() {
echo
"ns1\\ns1\\ns1c::write()\n";
}
}
}

namespace
ns2 {
use
ns1\ns1 as ns1; // both a class in ns1, and a namespace ns1\ns1

// the next class causes fatal error in php 5.6, not in 7.0
class ns1 {
public static function
write() {
echo
"ns2\\ns1::write()\n";
}
}

ns1::write(); // calls imported ns1\ns1::write()
ns1\ns1c::write(); // calls imported ns1\ns1\ns1c::write()
namespace\ns1::write(); // calls ns2\ns1::write()
}
?>
up
2
theking2 at king dot ma
1 year ago
Just like class names currently namespaces are not case sensitive. So no errors will be shown here:

<?php declare(strict_types=1);
namespace
Foo;
class
Bar {
public function
__construct() {
echo
'Map constructed';
}
}

$foobar = new \foo\bar();
up
6
phpcoder
9 years ago
Regarding "Neither functions nor constants can be imported via the use statement." Actually you can do it in PHP 5.6+:

<?php

// importing a function (PHP 5.6+)
use function My\Full\functionName;

// aliasing a function (PHP 5.6+)
use function My\Full\functionName as func;

// importing a constant (PHP 5.6+)
use const My\Full\CONSTANT;
?>
up
-4
okaresz
10 years ago
To correct manolachef's answer: define() ALWAYS defines constants in the GLOBAL namespace.

As nl-x at bita dot nl states in the note at http://www.php.net/manual/en/function.define.php, the constant "NULL" can be defined with define() case-sensitively, but can only be retrieved with constant(), leaving the meaning of NULL uppercase keyword as the only value of the type null.
To Top