Traits in PHP 5.4.0 - Part 1: Comparison

04.03.2012

Größer-Kleiner-Vergleiche sind häufig. So können einfache Zahlen verglichen werden, Volumina, Vermögen, Längen, Flächen und vieles mehr. Eine schöne Möglichkeit für dieses geradezu klassische Beispiel eines Traits:

trait Comparable{
	abstract function isGreaterThan($other);

	function isLesserThan($other){
		return $other->isGreaterThan($this);}

	function isLesserThanOrEqualTo($other){
		return !$this->isGreaterThan($other);}

	function isGreaterThanOrEqualTo($other){
		return !$other->isGreaterThan($this);}

	function doesNotEqual($other){
		return $this->isLesserThan($other) || $this->isGreaterThan($other);}

	function equals($other){
		return !$this->doesNotEqual($other);}}

Es reicht für eine Klasse, die abstrakte Methode isGreaterThan($other) zu implementieren, um alle anderen Methoden zu erhalten.

Eine (zugegebenermaßen wenig sinnvolle) Beispiel-Klasse, die den Trait Comparable benutzt:

class IntValue{
	use Comparable;

	private $value;

	public function __construct($value){
		$this->value = $value;}

	public function raw(){
		return $this->value;}

	public function isGreaterThan($other){
		return $this->value > $other->raw();}

	public function __toString(){
		return $this->value.'';}}

Natürlich hätte man in diesem Fall auch klassische Vererbung verwenden können, um den gleichen Effekt zu erzielen. Doch wo eine IntValue-Klasse existiert, könnte es auch BoolValue, DoubleValue und andere geben, die dann eventuell refactort werden würden, um von einer gemeinsamen Elternklasse PrimitiveValue zu erben. Damit könnte IntValue nicht mehr gleichzeitig von einer möglichen Comparable-Klasse erben. Das ist nur möglich, wenn Comparable ein Trait ist.

Doch wie funktioniert das genau? Am einfachsten ist es, sich das Nutzen eines Traits als Einbinden vorzustellen – konkrete Methoden des Traits verhalten sich so, als wären sie per Copy&Paste direkt in die Klasse eingefügt worden. Abstrakte Methoden haben die gleiche Wirkung wie abstrakte Methoden einer Elternklasse oder eines Interfaces, sie erfordern eine Implementierung oder, dass die Klasse selbst als abstrakt markiert wird.

Dieser Code, zusammen mit einer weiteren Klasse, die Comparable nutzt, und einem Test-Skript, als Archivdatei: comparison.tar.bz2