2013-06-09 10 views
23

クラスの2つのインスタンスを比較するタイミングをPHPで定義するパターンやマジックメソッドはありますか?JavaにあるようなPHPに__equalsメソッドがありますか?

たとえば、Javaでは簡単にequalsメソッドをオーバーライドし、2つのインスタンスをチェックして比較するカスタム方法を作成できます。

+0

同じインスタンスのオブジェクトまたは同じクラスの2つのオブジェクトインスタンスを比較しますか? [the manual](http://php.net/manual/en/language.oop5.object-comparison.php)をチェックしましたか? – dbf

+0

Javaには魔法のメソッドがありませんので、あなたが何を求めているのか分かりません。確かに、Javaのようにできるだけメソッドを追加することができます。 –

+2

'$ ClassA === $ ClassB'を比較するのではなく、equalsを自分で実装するだけで、' $ ClassA-> equals($ ClassB) 'を実行できます。 – halfer

答えて

21

本文はどこですか?いいえ、__equalsの魔法はありません。 in the manualの魔法の完全なリストがあります。

あなたは、彼らが同じ属性と値を持ち、同じクラスのインスタンスである場合は、それらは等しく考慮します

$myObject1 == $myObject2 

を行うことができます。

私はこのタイプのメソッドを自分自身でしばしば望んでいましたが、より有用なものは比較演算子<>、==、===などのために呼び出される__compare()メソッドですPHP internals wikiに見られるようにPHPの作り付けのクラスのために存在し、PHPInternals bookで実施することができる方法の例があります: - compare_objects

int (*compare)(zval *object1, zval *object2 TSRMLS_DC) 

は、2つのオブジェクトを比較し

が。演算子==、!=、<、>、⇐および> =に使用されます。 実装は、これらの規則に従わなければならない - 同じ比較ハンドラを共有し、b、cのいずれかのオブジェクトのために:私はこれを達成するために使用している

一つの方法は、Comparableインタフェースを実装することで、のようなもの: -

interface Comparable 
{ 
    /** 
    * @param Comparable $other 
    * @param String $comparison any of ==, <, >, =<, >=, etc 
    * @return Bool true | false depending on result of comparison 
    */ 
    public function compareTo(Comparable $other, $comparison); 
} 

オブジェクト比較の詳細、およびOOP関連のその他すべてについては、http://www.php.net/manual/en/language.oop5.phpを参照してください。

This may be implemented in PHP 7。誰もが言うように

+0

比較で-1(小さい)、0(等しい)、1(大きい)が返されるため、2番目の引数は正しくありません。 – Fleshgrinder

+0

@Fleshgrinder PHPで動作するかどうかは現在わかりません。 O: – vascowhite

+0

C、Javaなどの比較メソッドと、PHP自体の比較関数とメソッドをチェックしてください。彼らは常にそれらの番号の1つを返します。 'usort'コールバックは、それらの番号の1つを返すためにも必要です。このスレッドで私の追加答えを見てください。 – Fleshgrinder

1

基本的には、これが行います。

$object1 == $object2 

は種類とプロパティを比較します。


しかし、私はこのケースではない、私は私の平等方法をカスタマイズしたい場合、私は平等を主張したいのクラスでのマジックメソッド__toString()を実装しています。

class Car { 
    private $name; 
    private $model; 
    ... 
    public function __toString() { 
    return $this->name.", ".$this->model; 
    } 
} 

そして私は、私はちょうどこれを行う比較ですやりたい:

$car1->toString() === $car2->toString() 

をそして2つのインスタンスが同じ属性を持っている場合、それが比較されますが。

他のオプション(コメントのhalfer状態として)は、同じクラスの別のインスタンスの等価性をアサートするequalメソッドを実装しています。例:

class Car { 
    private $name; 
    private $model; 
    ... 
    public function equals(Car $anotherCar) { 
     if($anotherCar->getName() !== $this->name) { 
      return false; 
     } 

     if($anotherCar->getModel() !== $this->model) { 
      return false; 
     } 
     ... 
     return true; 
    } 
} 
7

悲しいことですが、あなたは非常に簡単に何かを複製できます。例: -

これはあまり優雅ではありませんが、あなたを邪魔しないでください。

アンソニー。

+0

これは、実際には、インタフェース内の 'IComparable'と' Foo'の 'Foo'を指し示す' self'の使用による致命的なエラーに終わるので、実装は契約を履行しません。 – Fleshgrinder

0

カスタムオブジェクトを比較したい場合、あなたはこのようにそれを行うことができます。

$time1 = new MyTimeClass("09:35:12"); 
$time2 = new MyTimeClass("09:36:09"); 

if($time1 > $time2) echo "Time1 is bigger"; 
else echo "Time2 is bigger"; 

//result: Time1 is bigger 

をそれはクラスで見つかった最初のプロパティを比較して、私の場合は合計秒数を保持しているint値与えられた時間に。 $ secondsプロパティを上に置くと、予期しない 'Time1 is larger'が返ってくることがわかります。

class MyTimeClass { 
    public $intValue; 
    public $hours; 
    public $minutes; 
    public $seconds; 

    public function __construct($str){ 
     $array = explode(":",$str); 
     $this->hours = $array[0]; 
     $this->minutes = $array[1]; 
     $this->seconds = $array[2]; 
     $this->intValue = ($this->hours * 3600) + ($this->minutes * 60) + $this->seconds; 
    } 
} 
3

最初に==オペレータをオフにすることは、ほとんどの場合、特に値オブジェクトについて話している場合は十分です。インスタンスをスカラー値と比較するには、__toStringメソッドを指定してください。

<?php 

final class ValueObject { 

    private $value; 

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

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

} 

$a = new ValueObject(0); 
$b = new ValueObject(1); 

var_dump(
    $a == $b, // bool(false) 
    $a == $a, // bool(true) 
    $b == $b, // bool(true) 
    $a == '0', // bool(true) 
    $b == '1' // bool(true) 
); 

これで1つの落とし穴があり、それはインスタンスを所望の値に変換することができなかったと文句を言うだろうので、あなたは(少なくともないPHP 5や7での)文字列以外のスカラー型に比較することはできません。したがって、比較する値の型が文字列であることを常に確認する必要があります。

あなたは、入力を小文字にしたい、または特定の精度まで浮動小数点値を処理したい場合は、別のアプローチが必要です。これを処理する1つの方法は次のとおりです。

<?php 

interface Comparable { 

    function compareTo(Comparable $other): int; 

} 

function class_compare(Comparable $a, Comparable $b): int { 
    return $a->compareTo($b); 
} 

final class C implements Comparable { 

    private $value; 

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

    public function compareTo(Comparable $other): int { 
     assert($this instanceof $other && $other instanceof $this); 

     return $this->value <=> $other->value; 
    } 

} 

$c1 = new C(0); 
$c2 = new C(0); 

var_dump($c1->compareTo($c2)); // int(0) 

$c0 = new C(0); 
$c1 = new C(1); 
$c2 = new C(2); 

$actual = [$c2, $c1, $c0]; 
usort($actual, 'class_compare'); 

var_dump($actual === [$c0, $c1, $c2]); // bool(true) 

assertは、PHPにジェネリックスがないため、重要です。これは非常に悲しいものですが、これを実装する方法はありません。

私がする傾向は次のとおりです。

<?php 

final class SomeClass { 

    private $value; 

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

    public static function compare(SomeClass $a, SomeClass $b): int { 
     return $a->compareTo($b); 
    } 

    public function compareTo(SomeClass $other): int { 
     return $this->value <=> $other->value; 
    } 

    public function isEqual($other): bool { 
     return $other instanceof $this && $other->value === $this->value; 
    } 

    public function isIdentical($other): bool { 
     return $other instanceof $this && $this instanceof $other && $other->value === $this->value; 
    } 

} 

これらのメソッド名を慣習的に守るだけで、適切に使用することができます。複数のクラス間で所望のデフォルト動作を実装するための特性を提供することさえできます。

+0

'$ this instanceof $ other'と' $ other instanceof $ this'の両方をアサートする必要がありますか?これらの2つの比較が異なる結果をもたらすときのヒント? – GeorgeK

+1

必要ではありませんが、それはあなたが望むものによって異なります。 '$ other instanceof $ this'は、' $ other'が '$ this'か' $ this'のサブクラスのいずれかであることを意味します。 '$ this'は' $ other'のインスタンスでなければならないので、次のチェックではサブクラスは許可されません。 – Fleshgrinder

関連する問題