Organizando seu código com namespace

Quando estamos começando em PHP, normalmente, uma das primeiras coisas que aprendemos é a incluir um script dentro do outro:

include(“meuArquivo.php”);

Assim a gente evita muita repetição de código e consegue fazer os scripts interagirem entre si. E, com isso, surge na nossa vida o famoso include.

Entretanto, nem só de script é feito um bom desenvolvedor. E quando começamos a nos aventurar em orientação a objetos surge o namespace! E com ele vem a necessidade de utilizar o use:

namespace meu\namespace;

use meuArquivo;

Mas, muitas vezes, os porquês desse processo acabam ficando meio obscuros.

Trabalhando sem namespace

Vamos supor que precisamos realizar o login do nosso sistema PHP. Um dos conceitos mais básicos da orientação a objetos é que se precisamos representar algo, criamos uma classe.

Logo, para resolver nosso problema, precisaremos criar uma classe de Login. Algo como, dentro de um arquivo Login.php:

class Login{
    //métodos e atributos necessários para realizar um login
}

Perfeito! Com nossa classe login conseguimos modelar uma forma para nosso usuário passar pela validação do sistema. Portanto, no nosso sistema, se quisermos realizar um login podemos usá-la:

include(“class/Login.php”);

class Sistema{
    public function realizaLogin($usuario,$senha){
        $login = new Login();
        // popula o login e realiza as verificações
    }
}

Aqui, incluímos nosso arquivo Login.php no Sistema para que pudéssemos criar um novo Login e usar nossa classe.

Porém, em softwares modernos, temos apenas uma forma de login? É muito comum nos dias de hoje um sistema ter diversas formas de login por API, certo? Um exemplo disso são os logins pelo facebook, google plus, etc.

Se a gente teve a necessidade de criar uma classe Login para modelar a nossa forma de passar pela validação, é bem possível que essas APIs tenham feito a mesma coisa e também criaram seu arquivo Login.php, para descrever como o login deles funciona. Algo como:

class Login{
    //métodos e atributos necessários para realizar um login através da API
}

Repare que temos uma class Login.php para nosso sistema, outra para a conexão de API. Será que até aqui já temos algum problema? Se pararmos para analisar, temos duas classes com o mesmo nome! Mas, isso resolvemos fácil. Basta trocar elas de pasta, deixando nossa estrutura parecida com:

NossoProjeto
    class
        Sistema
        Login
    api
        Login

Mas, no nosso sistema, precisariamos criar nosso login e o login da api, certo? Algo como:

include(“class/Login.php”);
include(“api/Login.php”);

class Sistema{
    public function realizaLogin($usuario,$senha){
        $login = new Login();
        // popula o login e realiza as verificações
    }

		public function realizaLoginApi($email,$senha){
				$login = new Login();
				// realiza a lógica de validação da api
		}
}

Agora temos que dar new em 2 Login. Para isso, incluimos nossa classes de Login e a classe de Login da API. Mas, como o PHP vai saber de qual Login estamos falando quando demos new? Ambas as classes têm o mesmo nome!

Uma solução era mudar o nome de uma delas. Como normalmente não mexemos nos arquivos externos, mudaríamos nossa classe Login para algo como LoginInterno.

include(“class/LoginInterno.php”);
include(“api/Login.php”);

Class Sistema{...

O que não faz sentido algum já que se a classe de Login está dentro do nosso projeto, é evidente que esse Login é interno!

Nesse caso estaríamos perdendo a semântica do nosso código por um problema de estrutura: não temos como diferenciar classes com o mesmo nome.

Agora com namespace

Podemos dizer para o PHP que queremos diferenciar nossas classes da mesma forma que colocamos os arquivos em pastas no nosso sistema operacional. Mas, agora, ao invés de separar nossos arquivos em pastas, separamos em namespaces!

Como a estrutura de pastas de um sistema costuma ser bem organizada é muito comum a gente utilizar a própria estrutura de pastas para declarar nosso namespace.
Algo como:

Login.php

namespace class;

class Login{
    //métodos e atributos necessários para realizar um login através da API
}

Como a classe Login está dentro da pasta class, colocamos ela no namespace class.

Mas, e os nomes iguais?

Perfeito, nosso problema está resolvido! Colocamos nossas classes em namespaces diferentes e podemos usá-los, mas ainda temos um pequeno problema:

use class\Login; // estamos usando a classe Login dentro do namespace class!
use api\Login; //estamos usando a classe Login do namespace api!

class Sistema{
		public function realizaLogin($usuario,$senha){
				$login = new Login(); // de qual login estamos falando?
				// popula o login e realiza as verificações
		}

		public function realizaLoginApi($email,$senha){
				$login = new Login(); // de qual login estamos falando?
				// realiza a lógica de validação da api
		}
}

Ainda estamos tentando dar new nas classes com o mesmo nome. Por isso, quando usamos namespaces podemos dar apelidos (alias) para nossas classes! Algo como:

use class\Login;
use api\Login as LoginApi; // mudamos o nome da classe

class Sistema{
		public function realizaLogin($usuario,$senha){
				$login = new Login();
				// popula o login e realiza as verificações
		}

		public function realizaLoginApi($email,$senha){
				$login = new LoginApi();
				// realiza a lógica de validação da api
		}
}

Agora sabemos exatamente que a classe LoginApi está relacionada ao namespace api sem mexer em nenhuma outra linha de código. Tornamos nosso código muito mais semântico, flexível, evitamos conflitos e ainda conseguimos organizar na mesma estrutura das pastas!

Algo que jamais conseguiríamos apenas com o include, afinal ele apenas inclui o conteúdo do arquivo. O conceito de namespace é algo extremamente importante de se entender para mantermos um código bem organizado e orientado a objetos.

Com o use, não estamos mais presos a uma string com o diretório do arquivo, o que evita problemas com o diretório exato. Temos uma forma elegante de lidar com a duplicidade das classes!

Claro que, isso não exclui completamente a utilidade dos includes. Ainda temos a necessidade de carregar os arquivos que vamos utilizar, porém podemos fazer isso com um único arquivo de autoload que carrega tudo pra gente.

Qualquer projeto grande, inclusive frameworks como laravel e symfony, trabalham com namespaces e utilizam autoload para incluir os arquivos. Para facilitar essa inclusão, surgiram alguns padrões de desenvolvimento mais conhecido como Php Standard Recommendation (PSR). Se você quiser saber mais sobre PSRs, tem um outro post aqui no blog sobre boas práticas em PHP e PSRs.

Aqui na alura, a gente sempre se preocupa com boas práticas. Se você quiser saber mais sobre boas práticas em PHP, da uma olhada no curso de design patterns =)

E você, o que achou de namespaces? Vai usar nos seus projetos? Compartilha com a gente!

(Última atualização em: 10 de março de 2017)

Próximo Artigo7 ferramentas que podem ser boas alternativas ao Photoshop