PHP/クラス

本章では、PHPにおけるオブジェクト指向プログラミングの基礎について説明します。オブジェクト指向は、現代のプログラミング言語で広く採用されているパラダイムであり、PHPでも重要な概念の一つです。
PHPのオブジェクト指向は、バージョン5から導入され、現在ではPHP 8.xまで進化を遂げています。オブジェクト指向プログラミングには、クラス、オブジェクト、継承、ポリモーフィズムなどの概念があり、これらを理解することでより柔軟かつ効率的なプログラムを作成することができます。
本章では、オブジェクト指向の基本的な概念から始め、クラスの定義、オブジェクトの生成、メソッドの呼び出し、継承などを順に説明していきます。また、実際の例を交えて、具体的なプログラムの作成方法を解説します。
オブジェクト指向は、初心者にとっては難しいと感じるかもしれませんが、一度理解してしまえば、より高度なプログラミングを行うことができます。本章を通じて、オブジェクト指向プログラミングについてしっかりと理解し、PHPのプログラミング能力を向上させてください。
PHPのオブジェクト指向の主な特徴は以下の通りです。
PHPのオブジェクト指向プログラミングの長所と短所については以下の通りです。
【長所】
【短所】
学習コストが高くなる: オブジェクト指向プログラミングは、手続き型プログラミングに比べて、抽象的な概念が多く登場するため、学習コストが高くなることがあります。
クラス Hello は、privateアクセス修飾子を持つ$whoプロパティを持ち、__construct()メソッドで初期化されます。__construct()メソッドは、クラスがインスタンス化されたときに呼び出され、引数 $who が渡された場合は、それを$this->who に設定します。引数が渡されない場合は、デフォルトで "World" を設定します。
greet() メソッドは、インスタンスの $who プロパティを使用して、 "Hello {who}!" というメッセージを表示します。PHP_EOLは、プラットフォームに依存しない改行コードです。
次に、$helloという名前の Hello クラスのインスタンスを作成し、greet() メソッドを呼び出します。これにより、「Hello World!」が表示されます。次に、$universeという名前の別の Hello クラスのインスタンスを作成し、greet()メソッドを呼び出します。これにより、「Hello Universe!」が表示されます。
コンストラクターとプロパティは、クラスにおいて重要な役割を果たします。コンストラクターは、インスタンス化されたオブジェクトの初期化を行うためのメソッドであり、プロパティはオブジェクトのデータを表すためのメンバー変数のようなものです。
アクセス修飾子は、コンストラクターとプロパティのアクセスレベルを定義するために使用されます。アクセス修飾子は、public、private、protectedの3つがあり、それぞれ以下のような意味を持ちます。
また、プロパティの値を初期化後に変更できないようにするには、readonly修飾子を使用することができます。readonly修飾子は、一度設定された値を変更できないプロパティを定義する場合に便利です。
これらの修飾子を適切に使うことで、コードの保守性や安全性を高めることができます
このコードは、PHP 8から導入された、コンストラクター引数にアクセス修飾子を組み合わせてプロパティを定義することができる機能を使用しています。また、readonly修飾子を使用して、値を一度設定した後に変更できないようにプロパティを定義しています。
具体的には、Hello2クラスでは、コンストラクターの引数として、public修飾子とreadonly修飾子が指定されたwhoという名前のstring型のプロパティを定義しています。コンストラクターでは、このプロパティに初期値が設定されます。greetメソッドは、このプロパティの値を用いて、Helloというメッセージを出力するために使用されます。
このクラスのインスタンスを生成する際には、コンストラクターに引数を渡すことができます。Hello2のインスタンスを生成する際に引数を渡さない場合、whoプロパティの値は "World" に設定されます。引数を渡した場合は、その値がwhoプロパティに設定されます。
また、コードの最後の行では、インスタンスが生成された後にプロパティの値を取得し、出力しています。その後、whoプロパティを書き換えようとしている行がコメントアウトされています。これは、readonly修飾子を使用してwhoプロパティが一度設定された後に変更できないようにしているため、エラーが発生します。
デストラクターとは、オブジェクトが破棄される際に自動的に呼び出される特殊なメソッドです。デストラクターは、クラス定義内に __destruct() という名前で定義されます。デストラクターは、インスタンスを参照する変数が1つもなくなると自動的に呼び出され、そのインスタンスに関連する資源を解放するために使用されます。資源は、メモリ、ファイル、データベース接続など様々です。
また、readonly 修飾子を使用して、初期値から変更できないプロパティを作成することもできます。以下は、readonly 修飾子を使った例です。
このコードでは、クラス MyClass のインスタンスが作成され、参照が $obj で保持されます。
その後、$obj の複製が $o2 に作成され、参照がコピーされます。
次に、$obj に null が代入されることで、$obj からの参照はなくなりますが、$o2 からの参照は残っています。
最後に、$o2 に null が代入されることで、すべての参照がなくなります。
その結果、MyClass::__destruct() が暗黙的に呼び出されます。
__destruct() は、オブジェクトが破棄される際に自動的に呼び出される特殊なメソッドであり、この例ではクラス名と "done!" という文字列が出力されます。
PHPには、動的プロパティ(dynamic properties)という機能があります。これは、オブジェクトのプロパティを実行時に定義することができる機能です。しかし、動的プロパティは1つのタイポで意図しないプロパティを作ってしまい、非常に危険であり、プログラムのメンテナンス性を低下させる可能性があります。そのため、PHPでは動的プロパティの使用を非推奨としており、代わりに __get() と __set() メソッドを使用することを推奨しています。
__get() メソッドは、オブジェクトのプロパティにアクセスする際に、存在しないプロパティにアクセスした場合に呼び出されます。このメソッドを実装することで、存在しないプロパティにアクセスされた場合に特定の処理を行うことができます。
__set() メソッドは、オブジェクトのプロパティに値を設定する際に、存在しないプロパティに値を設定しようとした場合に呼び出されます。このメソッドを実装することで、存在しないプロパティに値を設定された場合に特定の処理を行うことができます。
これらのメソッドを使用することで、動的プロパティの使用を避け、プログラムのメンテナンス性を向上させることができます。
このコードは、クラス Simple を定義し、その中にプロパティ $prop1 を宣言しています。その後、インスタンス $instance を作成し、そのプロパティ $prop1 にアクセスして値を表示し、get_object_vars() 関数を使用して、オブジェクトのプロパティの一覧を表示しています。この結果、$instance->prop1 の値が 1 で、get_object_vars() 関数が $prop1 を返していることがわかります。
次に、$instance->prop42 というプロパティに値 42 を設定して、その値を表示し、再度 get_object_vars() 関数を使用して、オブジェクトのプロパティの一覧を表示しています。この結果、$instance->prop42 の値が 42 で、get_object_vars() 関数が $prop1 と $prop42 を返していることがわかります。
このように、PHPでは、既存のプロパティの他に、動的に新しいプロパティを追加することもできます。また、get_object_vars() 関数を使用することで、オブジェクトのプロパティを一覧できます。
__setと__getは動的プロパティへの代入と参照をインターセプトする特殊関数で、いわゆるアクセサです。
このコードは、クラス Simple を定義し、その中で __get() メソッドと __set() メソッドを実装しています。
__get() メソッドは、オブジェクトのプロパティにアクセスする際に、存在しないプロパティにアクセスした場合に呼び出されます。このメソッドを実装することで、存在しないプロパティにアクセスされた場合に特定の処理を行うことができます。この例では、プロパティ名をキーとして配列 $ary から値を取得しています。
__set() メソッドは、オブジェクトのプロパティに値を設定する際に、存在しないプロパティに値を設定しようとした場合に呼び出されます。このメソッドを実装することで、存在しないプロパティに値を設定された場合に特定の処理を行うことができます。この例では、プロパティ名をキーとして配列 $ary に値を設定しています。
クラス Simple のインスタンスを作成し、そのプロパティにアクセスすると、__get() メソッドが呼び出されます。最初にアクセスしたプロパティは $prop1 であり、存在するプロパティであるため、その値が表示されます。また、get_object_vars() 関数を使用して、オブジェクトのプロパティを取得し、配列として表示しています。
次に、存在しないプロパティである $prop42 に値を設定します。このとき、__set() メソッドが呼び出され、配列 $ary に値が設定されます。その後、再び $prop42 にアクセスすると、__get() メソッドが呼び出され、配列 $ary から値が取得され、表示されます。また、get_object_vars() 関数を使用して、オブジェクトのプロパティを取得し、配列として表示しています。このとき、配列 $ary の内容も表示されます。

object (の公開プロパティ)を array(連想配列)に変換したり、array(連想配列)を object に変換することができます。 これは、「オブジェクトの配列」を使いたい場合、簡素に表現することを可能にします。
このコードは、配列とオブジェクトの相互変換の例を示しています。
配列 vect は、3つの要素を持ち、それぞれが name と age というキーを持つハッシュです。最初の foreach ループでは、vect の要素を一つずつ取り出して、array_map 関数を使って各ハッシュのキーと値を連結した文字列を作成し、それを implode 関数を使ってカンマで区切った一つの文字列にまとめて出力しています。
次に、array_map 関数と無名関数を使って、vect の各要素をオブジェクトに変換しています。このとき、array_map 関数の第二引数に渡している無名関数では、(object) キャストを使って、ハッシュをオブジェクトに変換しています。このようにすることで、各オブジェクトは name プロパティと age プロパティを持つようになります。
2つ目の foreach ループでは、配列 $objs の各要素を取り出して、name プロパティと age プロパティを連結した文字列を作成し、それを出力しています。最後に、各オブジェクトを array キャストを使って再びハッシュに変換し、キーと値を連結して文字列にして出力しています。
PHPの object は array と同じくイテレーション可能です。 object は、foreach で反復可能です。
クラスの継承に当たっては、可視性のコントロールに注意が必要です。
このコードは、クラスのプロパティにアクセスするために PHP の foreach ループを使用する方法について示しています。
また、public、protected、private プロパティへのアクセスについても説明しています。
プロパティ(インスタンス変数)は、それぞれのインスタンスを構成する要素ですが、クラスに属する変数=クラス変数、そしてクラスに属する定数=クラス定数を定義することができます。
このコードは、クラス定数とクラス変数についての基本的な使い方を示しています。
まず、クラス Math が定義され、クラス変数 var1 とクラス定数 pi と e が定義されています。var1 は public static で宣言されているため、クラスから直接アクセスできます。また、showVar1() メソッドと setVar1() メソッドがあり、それぞれクラス変数 var1 を参照して更新します。
まず、Math::$var1 で var1 の値を取得し、それを更新します。次に、showVar1() メソッドを呼び出して、クラス変数 var1 の値を表示し、setVar1() メソッドを使用して値を変更し、再度 showVar1() メソッドを呼び出して、変更された値を表示します。
次に、クラス定数 pi と e の値を表示し、showPI() メソッドを呼び出して、クラス定数 pi の値を表示します。
最後に、self キーワードを使用して、クラス変数とクラス定数にアクセスする方法を示しています。self::$var1 でクラス変数にアクセスし、self::pi でクラス定数にアクセスします。これらの値を echo ステートメントで出力します。
__ からはじまるメソッドは、マジックメソッドといい処理系が特定のタイミングで暗黙に呼出します。 このまでに紹介した、コンストラクターもデストラクターもマジックメソッドです。
他にも以下のようなマジックメソッドがあります。
これらのマジックメソッドは、クラス内で実装することができます。マジックメソッドを使うことで、より柔軟なオブジェクト指向プログラミングを行うことができます。ただし、適切に使わないとコードが複雑になってしまう場合もあるので、注意が必要です。
__toStringは、文字列を必要とする文脈にオブジェクトがあると呼出されます。
__get() と __set() ChatGPT __get() と __set() は、PHPにおいてマジックメソッドの一種であり、オブジェクトが存在しないプロパティにアクセスしたときに呼び出されます。
__get() は、存在しないプロパティにアクセスしたときに呼び出され、そのプロパティの値を返すために使用されます。以下は、__get() を使用してプロパティにアクセスする例です。
__set() は、存在しないプロパティに値を設定しようとしたときに呼び出され、そのプロパティの値を設定するために使用されます。以下は、__set() を使用してプロパティに値を設定する例です。
上記の例では、MyClassクラスに $data というプロパティがあります。このプロパティは private に宣言されているため、直接アクセスすることはできません。しかし、__get() メソッドを使用することで、存在しないプロパティにアクセスしたときに $data プロパティの値を返すことができます。また、__set() メソッドを使用することで、存在しないプロパティに値を設定し、その値を $data プロパティに保存することができます。
__get() と __set() は、プロパティを動的に取得または設定するための強力な方法です。しかし、過剰に使用すると、コードの可読性を低下させることがあるため、注意が必要です。
継承は、既存のクラスを拡張し、新しいクラスを作成するための機能です。継承により、新しいクラスは既存のクラスのプロパティやメソッドを引き継ぐことができます。
以下の例では、Personクラスを継承したStudentクラスを定義しています。
Personクラスは、$nameという保護されたプロパティと、__construct()とsayHello()という公開されたメソッドを持っています。__construct()は、インスタンスが作成されたときに実行される特別なメソッドであり、$nameプロパティを初期化します。sayHello()は、$nameプロパティの値を使用してメッセージを出力します。
Studentクラスは、Personクラスを継承しています。Studentクラスには、$studentIDというプライベートなプロパティと、__construct()とgetStudentID()というパブリックなメソッドがあります。__construct()は、Personクラスの__construct()メソッドを呼び出し、$nameプロパティを初期化し、$studentIDプロパティを設定します。getStudentID()は、$studentIDプロパティの値を返します。
以下のコードを使用することで、PersonクラスとStudentクラスを使用することができます。
継承を使用すると、コードの再利用性が向上し、冗長なコードを減らすことができます。 また、継承を使用することで、プログラムの柔軟性が向上します。例えば、新しいクラスを作成する際に、既存のクラスを継承することで、新しいクラスが既存のクラスの機能を引き継ぐことができます。 ただし、継承を過剰に使用すると、コードの複雑さが増し、メンテナンスが困難になる場合があります。継承を使用する際には、適切に設計し、必要な機能だけを継承するように心がけることが重要です。
抽象クラスとは、具体的な実装が不完全なクラスであり、継承することによってその実装を補完することを目的としたクラスです。抽象クラスは、abstractキーワードを使用して宣言します。抽象クラス自体はインスタンス化することができず、抽象クラスを継承する具象クラスで実装する必要があります。
以下は、PHPで抽象クラスを定義する例です。
上記の例では、Animalクラスを抽象クラスとして定義し、makeSound()メソッドを抽象メソッドとして宣言しています。具象クラスであるDogクラスとCatクラスは、Animalクラスを継承しています。DogクラスとCatクラスでは、Animalクラスで宣言された抽象メソッドmakeSound()を具体的に実装しています。
makeSound()メソッドは、犬が「Woof!」、猫が「Meow!」と鳴くように、各動物の鳴き声を出力します。DogクラスとCatクラスがAnimalクラスを継承しているため、Animalクラスで定義されたコンストラクタも呼び出されます。
最後に、DogクラスとCatクラスのインスタンスを作成し、makeSound()メソッドを呼び出すことによって、それぞれの動物の鳴き声を出力しています。
抽象クラスは、多くの具象クラスで共通するプロパティやメソッドを抽出し、再利用可能なコードを作成するのに役立ちます。また、抽象クラスは、継承することで必ず実装しなければならないメソッドを定義することができるため、クラスの機能や振る舞いを制限することができます。これにより、コードの信頼性や保守性を高めることができます。
例えば、動物クラスを抽象クラスとして定義した場合、多くの動物が鳴き声を出すことができるという共通点を抽出することができます。しかし、どのような鳴き声を出すかは動物によって異なります。そのため、抽象クラスでmakeSound()メソッドを定義し、具象クラスで実際の鳴き声を定義する必要があります。
また、抽象クラスは、インターフェースと似た役割を果たすことができます。インターフェースは、抽象メソッドのみを持つクラスであり、複数のインターフェースを実装することができます。一方、抽象クラスは、具象メソッドを持つことができ、単一の抽象クラスしか継承することができません。
抽象クラスは、継承することによってコードの再利用性を高めることができます。具象クラスは、抽象クラスのすべてのプロパティやメソッドを継承するため、共通の機能を持つクラスを簡単に作成することができます。また、抽象クラスは、具象クラスの実装を規定することができるため、開発者が間違った実装を行うことを防ぐことができます。
抽象クラスは、多くの具象クラスで共通する機能を抽出し、再利用可能なコードを作成することができます。また、抽象クラスは、具象クラスが必ず実装しなければならないメソッドを定義することができ、コードの信頼性や保守性を高めることができます。
トレイト (Trait) は、PHP5.4から導入された機能のひとつで、クラスで利用できるメソッドを、クラス継承の代わりに、再利用できるようにするための仕組みです。トレイトは、複数のクラスで共通する処理を定義することができます。
トレイトを定義するには、 trait キーワードを使います。トレイトを実装するクラスは、 use キーワードを使ってトレイトを指定します。トレイトに定義されたメソッドは、 use されたクラスのインスタンスから呼び出すことができます。
例えば、与えられた座標に移動する機能をもつ Point トレイトを定義しています。このトレイトには、コンストラクターで座標を設定する処理や、座標を文字列に変換する処理が含まれています。これらの処理は、 use するクラスで再利用することができます。
トレイトを利用することで、コードの再利用性を向上させることができます。しかし、トレイトを多用しすぎると、コードが複雑になり、メンテナンスが困難になる場合があるため、注意が必要です。
このコードは、トレイトを使用してクラスを構築する方法を示しています。
Point トレイトは、2つのプロパティ $x と $y を持つ __construct コンストラクターと、__toString マジックメソッド、および moveTo メソッドを定義しています。このトレイトは、他のクラスに追加することができ、そのクラスに Point の機能を提供することができます。
この例では、MyPoint クラスが定義され、Point トレイトが使用されています。MyPoint クラスには、自分で追加したメソッドやプロパティがなく、Point トレイトが提供するメソッドやプロパティを使用することができます。
最後に、MyPoint クラスのインスタンス $point が作成され、初期化子によって x と y の値が設定されます。次に、__toString メソッドが呼び出され、(1, 2) という文字列が表示されます。moveTo メソッドが呼び出され、x と y の値が変更されます。最後に、再度 __toString メソッドが呼び出され、(3, 5) という文字列が表示されます。
インターフェイスは、クラスがどのようなメソッドを提供する必要があるかを規定するために使用されるコードの抽象化です。 インターフェイスは実装を持ちませんが、そのメソッドの名前、引数の型、戻り値の型などを指定します。
インターフェイスは、クラスの柔軟性を高めるために使用されます。複数のインターフェイスを実装することで、複数の機能を提供できます。また、複数のクラスが同じインターフェイスを実装することで、コードを共通化することができます。
このコードは、Areableというインターフェイスを定義しています。インターフェイスは、クラスやトレイトが実装しなければならないメソッドを定義するためのものです。
Areableインターフェイスは、area()というメソッドを持っています。このメソッドは、戻り値がfloat型であることを示しています。具体的には、面積を計算してその値を返すことが期待されています。
例えば、正方形や円など、面積を計算する必要がある様々な図形がある場合、それらの図形を表すクラスを定義するときに、Areableインターフェイスを実装することで、各図形に対してarea()メソッドを提供することができます。
前二節で解説したトレイトとインターフェースを参照したクラス定義の例です。
このコードは、 Shape クラスが Areable インターフェースを実装し、 Point トレイトを使用していることを示しています。
Shape クラスのコンストラクターは、 Point トレイトで定義されたコンストラクターをオーバーライドしています。それにより、 Shape クラスが Point トレイトを使用しているときに、 Shape クラスのコンストラクターが呼び出されるようになります。
また、Shape クラスは __toString() メソッドを定義しており、これは Point トレイトで定義された同じメソッドをオーバーライドしています。これにより、 Shape オブジェクトを文字列として表現する際には、Point トレイトで定義された __toString() メソッドではなく、Shape クラスで定義された __toString() メソッドが呼び出されます。
注目したいのは、use文の中でPoint::__constructとPoint::__toStringを別名として宣言しています。 これによって、Shapeクラスが自身で実装した__constructと__toStringメソッドを持つことができます。 __constructメソッドでは、親トレイトの__constructを呼び出しています。 __toStringメソッドでは、親トレイトの__toStringを呼び出して、点の座標を文字列として返します。
最後に、 $shape オブジェクトを文字列として出力すると、 Shape クラスで定義された __toString() メソッドが呼び出され、 $shape --> (1, 2) という文字列が出力されます。
Enumをクラスと一緒に解説するのは奇異に感じられるかもしれませんが、言語処理系としては、Enumはclassのインフラを使って実装しているので、メソッドやメソッドのアクセス記述子などの働きは同じです。
このコードは、列挙型 (enum) Seasons を定義しています。
Seasons は4つの要素 Spring、Summer、Autumn、Winter を定義しています。この列挙型の各要素に対して、kanji メソッドが定義されています。kanji メソッドは、match 式を使用して、要素に対応する漢字名を返します。
もし match 式で、Seasons の列挙子を網羅していないと、 UnhandledMatchError がスローされます。これにより網羅性が担保されます。
このコードの最後では、Seasons 列挙型のすべての要素に対して、要素名と kanji メソッドの結果を出力しています。それぞれの要素名と漢字名の組み合わせが出力されます。
今節で取り上げた case に値を与えない Enum を Pure Enum といいます。 Pure Enum は UnitEnum interface の Implement です。
前節で紹介したEnumのように case が特定のスカラー値と結びついていない Enum を Pure Enum といいます。 これに対して、これから紹介する case にスカラー型とスカラー値を明示した Enum を Backed Enum といいます。
スカラー型を int と明示 この例では、W3C16 の値は int であり、明示的に int を指定しています。しかし、Enum では int 以外にも string が有効です。
異なる case に同じ値を割り当てることはできません(エラーになります)。 Enum では、異なる case に同じ値を割り当てることはできません。そのため、コード中で同じ値が割り当てられている case がある場合には、エラーが発生します。
Pure Enum の name に加え value もプロパティに持ちます。 Backed Enum では、各 case は value というプロパティを持ちます。このプロパティは、case の値を返します。また、name というプロパティも持ちます。
クラスメソッド from() は値から case を引きます。 Enum には、クラスメソッド from() があります。このメソッドを使うと、指定された値に対応する case を取得できます。ただし、無効な値を指定すると ValueError が発生します。
クラスメソッド tryFrom() は値から case を引きます。 Enum には、クラスメソッド tryFrom() もあります。このメソッドは、指定された値に対応する case を取得します。無効な値を指定すると、NULL が返されます。
Enum は、機能的には連想配列に似ていますが、Backed Enum では、各 case は一意であり、value も一意であることが保証されています。これにより、プログラマーは、例外処理などの面倒を省くことができます。一方、連想配列はキーが重複しないことが保証されますが、value が重複することがあるため、プログラマーが例外処理を実装する必要があります。

Backed Enum は BackedEnum interface の Implement です。
まとまった規模で、実用的な目的に叶うコードを読まないと機能の存在理由などの言語設計に思い至りにくいので、コードの断片から少し踏み込んだプログラムを掲載します。
PHPには複素数がないので、クラスとして実装しました。 ただ、8.1.13 の時点ではまだ演算子オーバーロードはないので、$x->add($y) のようにメソッドで実装しました。
このPHPスクリプトは、複素数を表現するComplexクラスを定義しています。複素数は、実数部分と虚数部分を持ちます。
Complexクラスのコンストラクタは、実数部分と虚数部分を初期化します。コンストラクタの引数には、float型のプロパティ$realと$imaginaryがあります。各プロパティは、引数のデフォルト値が0に設定されています。
__toString()メソッドは、Complexオブジェクトを文字列に変換するために使用されます。虚数部分が0の場合は、実数部分のみが表示されます。実数部分が0の場合は、虚数部分と文字"i"が表示されます。虚数部分が負数の場合は、負数を括弧で囲みます。それ以外の場合は、実数部分と虚数部分が+記号で連結され、文字"i"が追加されます。
coerce()メソッドは、$right引数をComplexオブジェクトに変換します。gettype()関数を使用して、$rightの型を確認します。integerまたはdoubleの場合、新しいComplexオブジェクトが作成され、$rightの値が実数部分に設定されます。objectの場合、get_class()関数を使用して、$rightがComplexオブジェクトであることを確認します。それ以外の場合、coerce()メソッドは例外をスローします。
add()メソッドとsub()メソッドは、複素数の加算と減算を行います。coerce()メソッドを使用して、引数をComplexオブジェクトに変換します。新しいComplexオブジェクトが作成され、$thisオブジェクトと$rightオブジェクトの実数部分と虚数部分が加算または減算されます。
abs()メソッドは、Complexオブジェクトの絶対値を計算します。絶対値は、複素数の実数部分の2乗と虚数部分の2乗の平方根です。
最後に、スクリプトは、Complexオブジェクトの作成と演算を実行して、結果を出力します。例えば、"$x + $y --> {$x->add($y)}"という行は、Complexオブジェクト$xと$yを加算し、結果を表示します。
図形クラス(Shape)から正方形(Square)や楕円形(Oval)などを派生しています。 Shape自身は、interface Areable の実装で、Areableは共通するメソッド area()を定義しており、area() を実装しないとShapeから派生できません。
このPHPコードは、幾何学的な形状(正方形、長方形、円、楕円)を表すために、トレイト(trait)を使用したオブジェクト指向プログラミングの例を示しています。
まず、Pointというトレイトを定義しています。このトレイトは、x座標とy座標を表すプロパティと、座標を移動するmoveToメソッドを持っています。
次に、Areableというインターフェイスを定義しています。このインターフェイスには、面積を返すareaメソッドが含まれています。
そして、Shapeクラスを定義しています。このクラスは、Pointトレイトを使用して、x座標とy座標を持っています。また、Areableインターフェイスを実装しており、areaメソッドをオーバーライドして0を返すようにしています。このクラスは、正方形、長方形、円、楕円の基底クラスとして使用されます。
Square、Rectangle、Circle、Ovalクラスは、Shapeクラスを拡張しています。それぞれが異なるプロパティを持っており、それぞれが面積を計算するためにareaメソッドをオーバーライドしています。
最後に、いくつかの形状のインスタンスを作成し、それらの面積を計算して表示するためのコードがあります。また、PointトレイトのmoveToメソッドを使用して、Ovalの座標を変更しています。
このプログラムは、オブジェクト指向プログラミングの基本的な概念を示しています。特に、クラスの継承、トレイトの使用、インターフェイスの実装などが重要な要素です。また、オブジェクトの状態を変更するメソッド(moveTo)を定義しています。