namespaces em php

Namespaces em PHP são utilizados para encapsular seu código e evitar colisões de nomes de funções, classes, interfaces e constantes.

Neste artigo você vai aprender a criar e utilizar namespaces de maneira adequada.

Então vamos lá.

O que são colisões de nomes?

Se você está iniciando com PHP, provavelmente o termo colisões de nomes deve soar estranho para você. Mas é algo bastante simples, vai por mim.

Quando criamos uma função, classe, constante ou interface, não podemos utilizar o mesmo nome no decorrer de nosso código. Veja um exemplo:

<?php
// Uma função sem ações
function teste () {}

// Mesmo nome: Fatal error: Cannot redeclare teste()
function teste () {}
?>

No exemplo acima, a segunda função com o mesmo nome da primeira, irá gerar um erro fatal.

E o mesmo ocorre para constantes:

<?php
// Uma uma constante
define('constante', true);

// Mesmo nome: Notice: Constant constante already defined
define('constante', true);
?>

Para classes:

<?php
// Uma classe
class teste{}

// Mesmo nome: Fatal error: Cannot redeclare class teste
class teste{}
?>

E para interfaces:

<?php
// Uma interface
interface teste{}

// Mesmo nome: Fatal error: Cannot redeclare class teste
interface teste{}
?>

Quando isso acontece, falamos que nosso código tem uma "colisão de nomes", que simplesmente indica que duas porções importantes do código tem o mesmo nome.

Como funcionam os namespaces em PHP?

Namespaces funcionam de maneira idêntica às pastas do seu computador, ou seja, dentro da pasta fotos, posso ter um arquivo chamado de minha_foto.jpg  e dentro da pasta documentos também posso ter um arquivo chamado minha_foto.jpg.

Mesmo que o arquivo minha_foto.jpg tenha o mesmo nome nas duas pastas, eles podem ser diferentes e seu conteúdo também pode ser diferente.

Em PHP, você pode ter vários namespaces (que seriam como as pastas) diferentes, e dentro desses namespaces, minhas funções, classes, interfaces e constantes. Se os namespaces forem diferentes, os nomes dos elementos dentro deles podem ser iguais a quaisquer outros nomes que existam em outros namespaces.

Porém, a mesma regra da colisão de nomes se aplica dentro de um namespace, ou seja, você não pode ter dois elementos de mesmo nome dentro de um mesmo namespace.

Como criar um namespace em PHP?

Para criar um namespace em PHP, simplesmente utilize a palavra chave {php}namespace{/php}, veja:

<?php
// Define o namespace
namespace MeuEspaco;

// Uma constante dentro do namespace MeuEspaco
define('MinhaConstante', 'Valor da constante');
?>

No trecho de código acima, criei um namespace chamado MeuEspaco e defini uma constante dentro desse namespace.

Repare que o trecho você deve definir o namespace na primeira linha do seu código, antes de qualquer coisa.

Como definir sub-namespaces em PHP?

Assim como as pastas (detalhado anteriormente) também é possível definir sub-namespaces (com pastas dentro de pastas), assim, você poderá organizar ainda mais seu código.

Para definir um sub-namespace, simplesmente utilize uma barra invertida seguida do nome do sub-namespace.

Veja:

<?php
// Define o sub-namespace
namespace MeuEspacoSubEspaco;

// Uma constante dentro do sub-namespace MeuEspacoSubEspaco
define('MinhaConstante', 'Valor da constante');
?>

Isso seria a mesma coisa que uma subpasta, ou seja, agora minha constante só estará acessível dentro do meu sub-namespace.

Criando vários namespaces em um mesmo arquivo

Namespaces são válidos para um arquivo apenas, porém, você pode definir vários namespaces dentro de um mesmo arquivo. Apesar de não ser recomendado fazer isso, segue um exemplo:

<?php
// Define o namespace
namespace MeuEspaco;

// Uma classe dentro do namespace MeuEspaco
class Teste 
{

}

// Define outro namespace
namespace OutroEspaco;

// Uma classe dentro do namespace OutroEspaco
class Teste 
{

}
?>

Você também pode utilizar chaves para definir seus namespaces, veja:

<?php
// Define o namespace
namespace MeuEspaco {

	// Uma classe dentro do namespace MeuEspaco
	class Teste 
	{

	}
	
}

// Define outro namespace
namespace OutroEspaco {

	// Uma classe dentro do namespace OutroEspaco
	class Teste 
	{

	}

}

// Código global
namespace {

	// Uma classe global
	class Teste 
	{

	}

}
?>

Assim você ainda pode misturar o código global, com namespaces diferentes. Perceba que mesmo que eu tenha uma classe declarada três vezes, no trecho acima, são três classes diferentes.

Vamos adicionar ações e executar essas ações para você entender melhor.

<?php
// Define o namespace
namespace MeuEspaco {

	// Uma classe dentro do namespace MeuEspaco
	class Teste 
	{
		public function __construct () {
			echo 'Classe está em ' . __NAMESPACE__ . '<br>';
		}
	}
	
}

// Define outro namespace
namespace OutroEspaco {

	// Uma classe dentro do namespace OutroEspaco
	class Teste 
	{
		public function __construct () {
			echo 'Classe está em ' . __NAMESPACE__ . '<br>';
		}
	}

}

// Código global
namespace {

	// Uma classe global
	class Teste 
	{
		public function __construct () {
			echo 'Classe está em ' . __NAMESPACE__ . '<br>';
		}
	}

	
	// Instanciando as classes
	$classe1 = new MeuEspacoTeste(); // Classe está em MeuEspaco
	$classe2 = new OutroEspacoTeste(); // Classe está em OutroEspaco
	$classe3 = new Teste();	 // Classe está em 
}
?>

Perceba também, que quando estou trabalhando com namespaces, não posso colocar código fora de um namespace qualquer. No trecho acima, defini os objetos das classes dentro do namespace global.

Observação: Em termos de programação, nunca crie namespaces diferentes, várias classes e nunca crie objetos de classes no mesmo arquivo. Um namespace deve valer para um único arquivo apenas, uma classe deve ser definida em seu próprio arquivo e instanciada fora desse arquivo.

A palavra mágica __NAMESPACE__

A palavra mágica __NAMESPACE__ carrega o nome do namespace que você está trabalhando, veja um exemplo:

<?php
// Define o namespace
namespace MeuEspacoSubEspacoQualqueCoisa;

echo __NAMESPACE__; // MeuEspacoSubEspacoQualqueCoisa
?>

Como utilizar namespaces em PHP

Certo, você aprendeu a criar namespaces e sub-namespaces, mas como vou utilizar isso em meu código?

Simples, para meu exemplo, vou criar dois arquivos diferentes, index.php e outroarquivo.php.

Veja o conteúdo do index.php:

<?php
// Define o namespace
namespace Index;

// Cria uma classe
class Classe
{
	// Construtor
	public function __construct () {
		echo 'Estou no ' . __NAMESPACE__ . '<br>';
	}
}

// Inclui o outro arquivo
include('outroarquivo.php');
?>

Perceba que estou incluindo o outroarquivo.php no index.php. Teoricamente, se eu tentasse instanciar a classe "Classe" no outro arquivo, daria certo, porém, como defini o namespace no index.php, terei um erro fatal:

<?php 
// Tento criar a instância: Fatal error: Class 'Classe' not found
$classeIndex = new Classe();
?>

Existem algumas maneiras diferentes para resolver este problema, uma seria definir o namespace Index no outro arquivo; outra seria chamar a classe pelo seu caminho completo, ou seja, namespacenomedaclasse.

Veja ambas as maneiras:

namespacenomedaclasse

<?php 
// Resultado: Estou no Index
$classeIndex = new IndexClasse();
?>

Definindo o namespace no outro arquivo

<?php 
// Define o namespace
namespace Index;

// Resultado: Estou no Index
$classeIndex = new Classe();
?>

Importando namespaces em PHP

Em PHP, você pode "importar" um namespace para outro nome (criar um alias).

Vamos continuar com nossos dois arquivos descritos no subtítulo anterior, não vou mudar o código do index.php, apenas do outroarquivo.php.

<?php
// Criando um aliás (atalho) para o namespace
use Index as a;

// Utilizando o atalho
$classe = new aClasse();
?>

No trecho acima a agora representa meu namespace Index.

Também posso importar quase tudo de outro namespace, menos funções. Veja:

<?php
// Criando um aliás (atalho) para a classe "Classe" dentro do 
// namespace Index
use IndexClasse as a;

// Utilizando novo nome da classe
$classe = new a();

// Resultado: Estou no Index
?>

Só para reforçar, isso só não funciona com funções.

Utilizando o espaço global dentro de um namespace

Dentro de qualquer namespace, é possível sobrescrever as funções nativas do PHP, porém, você ainda terá acesso a elas se utilizar uma barra invertida quando for utilizá-la, veja:

<?php
// Define o namespace
namespace Index;

// Criando uma função chamada trim dentro do namespace
function trim($valor) {
	// Remove espaços do início e do fim da string
	return preg_replace('/^s+|s+$/', '', $valor);
}

// Utilizando a função dentro do namespace
echo "'" . trim('  Teste de string  ') . "'"; // 'Teste de string'

// Utilizando a função nativa do PHP no espaço global
echo "'" . trim('  Teste de string  ') . "'"; // 'Teste de string'
?>

No exemplo acima, criei uma função chama "trim" que sobrescreve a função "trim" nativa do PHP, porém, ainda consegui utilizá-la em meu código, apenas adicionando uma barra invertida.

Isso pode ser feito com qualquer função.

Definindo constantes em namespaces

Se você quiser uma constante em um determinado namespace, simplesmente utilize a palavra chave {php}const{/php}. Veja:

<?php
// Define o namespace
namespace Index;

// Definindo a constante
const Constante = 'Valor';

// Mostra o valor da constante
echo Constante;

// Inclui o outro arquivo
include('outroarquivo.php');
?>

Para acessar o valor da constante fora de um namespace, simplesmente utilize seu nome completo, ou seja, namespacenomedaconstante.

<?php
// Acessando a constante do namespace Index
echo IndexConstante;
?>

Aprenda mais sobre namespaces em PHP

Se você ainda tem dúvidas, não hesite em questionar nos comentários, e sempre leia o manual do PHP, isso fará você ficar fera na linguagem e na programação, existem altas dicas na contribuição dos usuários.

Veja os links que vão te ajudar:

E não deixe de seguir todas as aulas do nosso curso gratuito de PHP e de PHP Orientado a Objetos.

Caso tenha dúvidas, pergunte aí abaixo, faremos questão de ajudar.