packages vs namespaces
Fala rapaziada, suave? Bom, ultimamente voltei a estudar java por motivos acadêmicos, e nesse retorno fui ver sobre packages e imports. E os achei, de certa forma, muito parecidos com os namespaces presentes no php. Com isso, fui explorar a aplicabilidade e funcionamento desses dois recursos, nessas duas respectivas linguagens.
Pra quem não conhece esse conceito ainda, segundo a w3schools, Namespaces
são qualificadores que resolvem dois problemas diferentes:
- Eles permitem uma melhor organização agrupando classes que trabalham juntas para realizar uma tarefa
- Eles permitem que o mesmo nome seja usado para mais de uma classe
Como já havia estudado esse conceito, ao me deparar com os packages em java, pensei ser a mesma coisa, só que se apresentando de uma maneira distinta, visto as linguagens serem diferentes.
php:
<?php
namespace php\entities {
class Person
{
function __construct(private string $name, private int $age)
{
}
function getName(): string
{
return $this->name;
}
function setName(string $name): void
{
$this->name = $name;
}
function getAge(): int
{
return $this->name;
}
function setAge(int $age): void
{
$this->age = $age;
}
function __toString()
{
return <<<PERSON
Person [
name={$this->name},
age={$this->age}
];
PERSON;
}
}
}
No php, o uso de namespaces faz com que se assuma uma organização lógica de classes. Ou seja, essa organização, necessariamente, não diz respeito a estrutura de diretórios do seu projeto.
onde a classe localizada em raiz-project/resources/Class.php
pode ter um namespace que seja diferente dessa estrutura.
Porém, no java não existe essa alternativa. Com o empacotamento seguindo, de certa forma, a estrutura de diretórios do projeto para que funcione.
java:
package com.galvao.mvn.studing.utils;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
E quando utilizo nomes distintos da estrutura de diretórios, ocorre esse aviso:
The declared package "studing.utils" does not match the expected package "com.galvao.mvn.studing.utils"Java(536871240)
Minhas dúvidas são: São realmente o mesmo conceito de organização? Se sim, porque um permite o nome distinto e o outro não.
São conceitos distintos? Se sim, quais suas diferenças?
PHP não tem autoload por padrão
A diferença é que o PHP não carrega os arquivos das classes automaticamente por padrao.
Isso significa que ao fazer
use Foo\Bar\Classe;
new Classe();
O PHP não entende aonde vai encontrar aquele arquivo.
Autoload e PSR-4
Porém, existe um recuros "magico" chamado autoload (https://www.php.net/manual/pt_BR/language.oop5.autoload.php) aonde você pode definir uma função que será responsável por carregar o arquivo que contém as classes.
E ai é que entra o PSR-4, um padrao de autoloading amplamente utilizado, inclusive pelo Laravel, e implementado pelo composer por exemplo.
Nele, o namespace segue o mesmo caminho da pasta do arquivo:
namespace VendorName\PackageName\Foo\Bar;
class Classe {
}
por exemplo, quando usando o autoloader do composer, irá apontar para o arquivo:
vendor\VendorName\PackageName\Foo\Bar\Classe.php
aonde o primeiro vendor
é algo específico do composer e não do PSR-4, pois é o diretório aonde o composer coloca os pacotes, para não misturar com o seu código.
Usando o autoloader padrão do composer, o código fica assim:
// obrigatoriamente você precisa carregar o autoloader do composer
// pois ele quem irá declarar a função de autoloader no PHP
require __DIR__ . '/vendor/autoload.php';
use VendorName\PackageName\Classe;
// por trás dos panos, o autoloader do composer irá executar um `require __DIR__ . '/vendor/VendorName/PackageName/Classe.php'
// e magicamente o codigo abaixo vai funcionar mesmo sem você ter requerido o arquivo manualmente
new Classe();