Orientação a Objetos – Métodos e atributos estáticos

orientacao-objetos-atributos-metodos-topo

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

Fonte: Thiago Belém

Postagens Relacionadas