Desenvolvimento - PHP

Orientação à Objetos em PHP – Métodos e atributos estáticos

Certo dia na faculdade estava vendo o código de um colega que está aprendendo PHP e comecei a discutir com ele algumas melhorias, o resultado final foi tão satisfatório e diferente do original que resolvi criar um post pra mostrar como o código evoluiu.

por Thiago Belem



O código original – Orientado à objetos ou PHP estruturado?

O código original já estava dentro de uma classe, mas não faria diferença nenhuma se fosse PHP estruturado… não lembro exatamente o nome dos métodos/variáveis, mas o restante está igualzinho:

class cFileType {
	
	function fImage($type) {
		switch($type) {
			case 'jpg':
			$bool = true;
			break;
			case 'png':
			$bool = true;
			break;
			case 'gif':
			$bool = true;
			break;
			default:
			$bool = false;
			break;
		}
		return $bool;
	}

}

A primeira mudança foi trocar esse switch, que não está fazendo nada além de definir o valor da variável $bool como true ou false se o $type for um dos valores válidos (jpg, png ou gif)… Nada melhor então do que usar a função in_array():

class cFileType {
	
	function fImage($type) {
		return in_array($type, array('jpg', 'png', 'gif'));
	}

}

WOW! Reduzimos de 21 para 7 linhas… mas ainda assim, se fosse estruturado não teria diferença nenhuma.

Meu amigo me disse que essa classe seria para verificar os tipos de arquivos (extensões), por exemplo “se é uma imagem” ou “se é um doc”… Então criamos outro método para verificar DOCs:

class cFileType {
	
	function fImage($type) {
		return in_array($type, array('jpg', 'png', 'gif'));
	}
	
	function fDoc($type) {
		return in_array($type, array('doc', 'docx'));
	}

}

Atributos, melhor tê-los

O código está melhorando, mas ainda assim tem algo errado… não é responsabilidade dos métodos fImage e fDoc saber a lista de extensões válidas… isso não deveria pertencer à classe como um todo e poder ser reutilizado?

class cFileType {

	public $image = array('jpg', 'png', 'gif');

	public $doc = array('doc', 'docx');
	
	function fImage($type) {
		return in_array($type, $this->image);
	}
	
	function fDoc($type) {
		return in_array($type, $this->doc);
	}

}

Atributos e métodos estáticos

Agora sim está parecendo uma classe normal, com atributos e métodos… Aí percebi que de orientada à OBJETOS essa classe não tem nada! Não estamos trabalhando com objetos.. O uso atual dessa classe seria assim:

$cFileType = new cFileType();
if ($cFileType->fImage('jpg')) {
	// É uma imagem válida
}

Eu não trabalho o objeto $cFileType, apenas instancio e utilizo um único modo… então vamos economizar um pouco de memória, transformando os métodos em métodos estáticos:

class cFileType {

	public static $image = array('jpg', 'png', 'gif');

	public static $doc = array('doc', 'docx');
	
	static function fImage($type) {
		return in_array($type, self::$image);
	}
	
	static function fDoc($type) {
		return in_array($type, self::$doc);
	}

}

E agora a utilização ficou um pouco mais simples:

if (cFileType::fImage('jpg')) {
	// É uma imagem válida
}

Sendo que você ainda pode usar o cFileType::image (pra ter uma lista de imagens válidas) em qualquer parte da sua aplicação sem instanciar a classe.

Reutilização de código

Segundo a abordagem DRY , não devemos nos repetir… Por isso aquele in_array()começou a me incomodar… Vai que você está verificando 30 tipos diferentes de arquivos, todos os métodos fazendo exatamente a mesma coisa… mas aí você decide mudar o in_array() pra algo mais eficiente ou aceitar até o caminho absoluto de um arquivo… vai mudar em 30 métodos na mão?

A responsabilidade de verificar se o valor $type tá dentro de uma “lista” válida não é dos métodos fImage e fDoc.. então vamos delegar:

class cFileType {

	public static $image = array('jpg', 'png', 'gif');

	public static $doc = array('doc', 'docx');

	static function fType($type, $list) {
		return in_array($type, $list);
	}
	
	static function fImage($type) {
		return self::fType($type, self::$image);
	}
	
	static function fDoc($type) {
		return self::fType($type, self::$doc);
	}

}

Agora se precisarmos mudar essa lógica de verificar se o $type tá dentro de uma “lista” válida, só vamos precisar mudar em um lugar só.

cFileType? fType? fImage? O resultado final

Temos que concordar que os nomes de classe e métodos escolhidos pelo meu amigo não são os mais intuitos… Então como uma modificação final, sugiro a seguinte classe devidamente renomeada:

class FileType {

	public static $image = array('jpg', 'png', 'gif');

	public static $doc = array('doc', 'docx');

	public static function isTypeInList($type, $list) {
		return in_array($type, $list);
	}
	
	public static function isImage($type) {
		return self::isTypeInList($type, self::$image);
	}
	
	public static function isDoc($type) {
		return self::isTypeInList($type, self::$doc);
	}

}

Com uma utilização bem simples e intuitiva:

if (FileType::isImage('jpg')) {
	// É uma imagem válida
}

Espero que tenham gostado!

Pra quem quiser ver o código completo da classe final, com os métodos comentados:https://gist.github.com/1338259

Artigo originalmente publicado por Thiago Belem: Orientação à Objetos - Métodos e atributos estáticos

Thiago Belem

Thiago Belem - Tenho 23 anos e trabalho com Desenvolvimento WEB há mais de 10 anos. Atualmente moro no Rio de Janeiro e, além de trabalhar como Freelancer, sou Professor no Assando Sites, meu curso online de CakePHP.