皆さん、健康診断の結果はどうでしたか?
えっ、またお医者さんに「太り過ぎ」と言われた?
奥さんに怒られるし、上司からも「痩せろ」と言われるしで、大変ですよね。
だったら、体重は private
プロパティーにして秘密にしておきましょう!
class Person
{
private $name;
// 最高機密
private $weight;
public function __construct($name, $weight)
{
$this->name = $name;
$this->weight = $weight;
}
}
はい、これで体重を隠せましたね。めでたしめでたし。
メソッドを追加してみる
でも、自分より太ってそうな、あの同僚の体重、知りたいですよね。1
はい、そんなあなたのために、こんなメソッド書いてみました。
class Person
{
private $name;
private $weight;
public function __construct($name, $weight)
{
$this->name = $name;
$this->weight = $weight;
}
/**
* 体重が同じかを比較する
*/
public function isWeightEqual($other)
{
return $this->weight === $other->weight;
}
}
あっ、でも $other->weight
は private
プロパティーだからダメなんじゃない?と思った方。
残念。これはちゃんと動きます。
$a = new Person("山田太郎", 60.5);
$b = new Person("田中次郎", 60.5);
var_dump($a->isWeightEqual($b)); //--> bool(true)
もっと頑張れば、isWeightGreaterThan()
とか isWeightLessThan()
とかも作れるでしょう。
体重を隠そうとしても無駄なんだぞ!
まじめに考えてみる
実は、PHP マニュアルの 他のオブジェクトからのアクセス権 にちゃんと書いてあります。
同じ型のオブジェクト間では、たとえ同一のインスタンスでなくても お互いの private メンバーや protected メンバーにアクセスすることができます。 これは、そのオブジェクトの内部ではオブジェクトの実装の詳細が既知であるからです。
なんか難しいこと書いてありますが、要するに 同じ型だったらインスタンスが違ってても private
や protected
メンバーにアクセスできるぞ と言っています。
なんでこんな面倒なことしてるの?
実は、この仕様、Java でも同じなのですが2、[Java]同一クラスであれば他インスタンスのprivateフィールドにアクセスできるのは何故か? という記事に、とても良いコメントを見つけました。
@shirakamus
もし private が thisからしかアクセスできない仕様だったら、equalsメソッドの実装はどうなるかな・・・
Java ではオブジェクトの比較は equals()
メソッドで行います。どのオブジェクトも、以下のような Object.equals()
を継承しています。
public boolean equals(Object o) {
return this == o;
}
通常はこれで十分なのですが、equals()
メソッドをオーバーライドすることもできます。たしか、こんな感じ。3
public class Person
{
private String name;
private double weight;
Person(String name, double weight)
{
this.name = name;
this.weight = weight;
}
@Override
public boolean equals(Object other)
{
if (this == other) {
return true;
}
if (other instanceof Person) {
Person person = (Person) other;
// private フィールドにアクセスしている!!!
return person.name == this.name
&& person.weight == this.weight;
}
return false;
}
}
重要なのは person.weight == this.weight
の部分です。
この person.weight
は、引数で渡されたインスタンスの private
フィールドですが、同じ Person
型なのでアクセスすることができるわけです。
もし、これが不可能だった場合、person.getWeight()
というように、わざわざゲッターを介したアクセスになるでしょう。
まとめ
PHP には Java のような equals()
は存在しませんが、思想としてオブジェクト指向を取り入れた際に、Java をはじめとするオブジェクト指向言語と同じような動きをするようにしたのでしょう(たぶん)。
まぁ、積極的に使うべきかと言われると、あんまり知られていないようにも思われるので、止めておいたほうがいいのかなとも思いますが。
あと、そもそも、痩せれば、こんな面倒なことまで気にしなくて済むはずです。
だから、お前は痩せたほうが良い。
(2018/1/13) サブタイトルを付けました。
-
知って何が楽しいかって? 「俺はあいつよりも痩せている」という優越感に浸りたいじゃないですか。 ↩
-
C++ や C# でも同様らしいです。privateメンバ変数へのアクセス 参照。 ↩
-
本当は
hashCode()
もオーバーライドしないといけないらしいけど、一旦、措いておきます。詳しくは equals をオーバーライドする時は一般契約に従う 参照。 ↩