Antevejo que no futuro, o PHP como uma linguagem iterativa e incremental que é, adicionará ao seu núcleo um recurso muito valioso na categoria orientação à objetos.
Antevejo ele, os Traits. E mais, consigo prever que será algo assim:
<?php
trait Hello {
public function ola() {
echo "Olá";
}
}
class Mundo {
use Hello;
public function world() {
echo "{$this->ola()} trait !";
}
}
$ola = new Mundo();
$ola->world();
// Olá trait !
Ok, não sou bidu. Realmente os Traits estão na lista do possível-futuro PHP 5.4 e eu, baixei a build de 31/03/2011 para testar.
Traits
O PHP não suporta herença multipla – amém – e por este motivo, às vezes ficamos limitados em algumas decisões de projeto (design). O maior problema neste ponto é que toda herença até agora (PHP 5.3.x) é vertical, ou seja, se eu precisar de um nível de abstração diferente no meio do processo, ou precisarei adicionar a nova abstração e reescrever tudo abaixo dela, ou ainda, terei que duplicar o código pois não conseguirei satisfazer a herença.
É nesse ponto que os Traits aparecem. Diferentemente da herença (vertical), os Traits possibilitam-nos criar herenças horizontais.
Exemplo, dada a necessidade: haverão Funcionários, Supervisores, Gestores e Diretores no sistema e estes possui em comum o fato de receber salário. (capitalismo). Uma possibilidade seria:
Pessoa > Funcionario Pessoa > Supervisores Pessoa > Gestores Pessoa > Diretores
Tudo perfeito. Porém, chega outra necessidade: Gestores e Diretores tem a capacidade de demitir. Gestores precisam gerenciar cronogramas, assim como os Supervisores fazem.
Pessoa.demitir(pessoa) não faz sentido, pois afetiria todos.
Gestor.demitir(pessoa) e Diretor.demitir(pessoa) atende, mas duplicaria o código.
Pessoa > Supervisor > Gestor Pessoa > Diretor
Shi, apareceu outro nível hierarquico. Traits auxilia exatamente neste ponto ! Vejamos:
Trait Cronograma Trait Evil (que contém recursos para demitir uma pessoa) Pessoa > Funcionario Pessoa > Supervisor : Cronograma Pessoa > Gestor : Cronograma : Evil Pessoa > Diretor : Evil
Note que o Pessoa > Supervisor : Cronograma – os dois pontos para indicar o Trait são de minha autoria – era o Pessoa > Supervisor antigo. Isso porque as atribuições para gerenciar cronogramas foram passadas para o Trait.
Neste pequeno exemplo, o Trait nos auxiliou com um problema de domínio. Acredito que ele também aplique-se e muito bem para problemas onde temos domínios transversais, pois, nele ficariam as atividades do outro domínio pode o domínio principal teria acesso aos recursos sem quebrar a SRP.
Traits em PHP
Como disse no começo, o futuro-provável PHP 5.4 virá com o Trait. Por enquanto essa implementação funcionaria:
<?php
trait Cronograma {
private static $ATRASADO = "sempre";
public function cobrarDe(Pessoa $funcionario) {
$funcionario->definirPressao(self::$ATRASADO);
$this->youTube();
}
private function youTube() {
}
}
class Funcionario extends Pessoa {
}
class Supervisor extends Pessoa {
use Cronograma;
}
$colaborador = new Funcionario();
$controlador = new Supervisor();
$controlador->cobrarDe($colaborador);
Os Traits possuem boas capacidades com métodos de instância e estáticos. Vamos explorar um pouco mais:
<?php
trait Hello {
public function sayHello() {
echo "Olá";
}
}
trait World {
public function sayWorld() {
echo "Mundo";
}
}
class View {
use Hello, World;
}
$view = new View();
$view->sayHello();
$view->sayWorld();
// exibe: Olá Mundo
Pegando informações da Classe
<?php
trait QuemSou {
public function eu() {
return get_class($this);
}
}
class Foo {
use QuemSou;
}
$foo = new Foo();
echo $foo->eu();
// exibe: Foo
Usando Variáveis de instância da classe
<?php
trait World {
public function help() {
return "{$this->hello} world";
}
}
class Hello {
private $hello = "Hello";
use World;
}
$hello = new Hello();
echo $hello->help();
// exibe: Hello world
Modificadores de acesso dos traits na classe
<?php
trait Hello {
public function ola() {
echo "Olá mundo";
}
}
class Modificadores {
use Hello { ola as private };
}
$ola = new Modificadores();
$ola->ola();
// Fatal Error....
Modificadores de acesso com alias para nome de método
<?php
trait Hello {
private function ola() {
echo "Olá mundo";
}
}
class Modificadores {
use Hello { ola as public aloha };
}
$ola = new Modificadores();
$ola->aloha();
// Olá mundo
Há outros vários recursos como métodos abstratos nos Traits, precedência, métodos estáticos, late static bindings, métodos mágicos, alias para nome de método do Trait ao usá-lo na classe. Para Rubistas ou Scalistas (?) as possibilidades são as mesmas dos Mixins e Traits de Ruby e Scala respectivamente.
- RFC do PHP Trait (offline por enquanto devido a problemas no servidor deles)



Traits, use com moderação. Excelente post Hélio.
Conforme já haviamos conversado, pessoalmente, acho problemático a utilização de Traits, principalmente porque diminui a ortogonalidade do código, ou em outras palavras, aumenta o acoplamento. Traits não é herança multipla porém pode trazer os mesmos problemas q a herança multipla trás. Por exemplo, quando se herda dois ou três métodos iguais, qual método terá validade?
Quando se pensaram na estrutura de orientação a objetos do Java, caparam a herança multipla e colocaram a idéia de interface, que evita ter esses tipos de problemas citados.
O pessoal do PHP, por um momento utilizou a estrutura de orientação a objeto similar a do java, porem, agora, estão caminhando no sentido contrário, retornando aos mesmos problemas que existem em C++
Al invés do pessoal do PHP ficar pensando em paradigmas de orientação a objeto, eles deveriam implementar multi-threads na linguagem, melhorar as bibliotecas de soap, conexão com db, etc. Isso é bem mais útil,
São pontos válidos, Isma!
No caso de “conflitos” de nomes em Traits diferentes, você é obrigado a declará-las na classe utilizando alias, caso contrário, Fatal Error é lançado.
Foi como o Lucas postou. Use-a com cuidado. É um recurso interessante e pode-nos poupar um bom tempo de manutenção. Hipoteticamente, imagine um Repositório qualquer. Tente imaginar como seria dentro dele, buscar uma conexão com o banco para utilizar nas pesquisas. Dependency Injection seria uma saída, porém, causaria duplicação de código em várias chamadas. Uma factory poderia auxiliar, mas um Trait caberia melhor neste ponto.
O PHP está seguindo para uma linha mais Scala/Ruby do que C++ ao meu ver. Tanto que a herença múltipla não existe – amém – ao invés, estão dando atenção aos Traits – já existentes nas citadas anteriormente.
O pessoal do core PHP não está importando-se tanto com OO, tanto que é um desenvolvedor fora do core que publicou a RFC da implementação. A Zend gostou e tudo indica que entrará no PHP 5.4 que virá brevemente.
Só para fechar: SOAP é falho e precisa de maior atenção, mesmo eu utilizando REST(ful) nos últimos tempos.
Abração rapaz !
Mesmo RESTFUL no PHP não é tão bem implementado. Ficar lendo php://input para capturar dados PUT e DELETE é uma coisa da época das pedras. Python, Java, Ruby tem implementações bem melhores para capturar os dados.
Outro problema é a caracteristica global que os dados de entrada tem. Pensando em OO, manter $_POST e $_GET com escopo global é bem feio.
É o nosso ganha-pão o PHP e creio que as críticas são feitas visando melhorar a linguagem. Mas merecem atenção do time de desenvolvimento da linguagem.
[...] Suporte a Traits (Leia mais na RFC para Horizontal Reuse e no site do @hlegius) [...]
Ótimo post, Hélio. No começo achei meio confuso, mas depois deu pra pegar bem a idéia. Tomada que venha realmente no PHP 5.4, pois é de bastante utilidade. Abraço!