プログラミング言語の原則としてよくみられるものに継承があります。 PHP はオブジェクトモデルにおいてこの継承を利用しています。 多くのクラスとオブジェクトとの連携に継承は関係しています。
例えば、クラスを拡張するとき、サブクラスは親クラスから public と、protected のメソッドや、プロパティや定数をすべて引き継ぎます。 (子の)クラスが親のメソッドを上書きしない限り、 親のメソッドの機能が保持されます。
これは、機能を定義して抽象化するのに便利です。 また、同じようなオブジェクトに機能を追加する際に、 共通機能を再実装する必要がなくなります。
親クラスの private メソッドは、子クラスからアクセスすることができません。 その結果として、子クラスは通常の継承のルールを無視して private メソッドそのものを再実装することができてしまいます。 しかし、PHP 8.0.0 より前のバージョンでは、final とstatic に関連する制限が private メソッドに適用されていました。 PHP 8.0.0 以降では、private メソッドの規則が強制されるのはprivate final として宣言されたコンストラクタのみになりました。 なぜなら、static として宣言されたファクトリメソッドを使う場合に、 コンストラクタを無効にする方法としてprivate final が用いられるからです。
メソッドやプロパティ、そして定数のアクセス権 に関するルールは、子クラスで緩めることが可能です。 たとえば、 親クラスでprotected なメソッドは 子クラスでpublic としてマークできます。 しかし、厳しくすることはできません。 つまり、親クラスでpublic なプロパティを 子クラスでprivate にすることはできません。 これの例外はコンストラクタです。 コンストラクタのアクセス権は厳しくすることができます。 たとえば、親クラスのpublic なコンストラクタは、 子クラスでprivate としてマークできます。
注意:
オートローディングが有効になっていない限り、 クラスの定義は実際に使うより前になければなりません。 別のクラスを継承したクラスの場合は、 そのクラスより前に親クラスが宣言されていなければなりません。 この規則が適用されるのは、別のクラスやインターフェイスを継承したクラスです。
注意:
読み取りと書き込みが両方可能なプロパティを、readonly として上書きしてはいけません。逆も同じです。
<?php
classA{
publicint $prop;
}
classBextendsA{
// 正しくありません: read-write -> readonly
public readonlyint $prop;
}
?>
例1 継承の例
<?php
classFoo
{
public functionprintItem($string)
{
echo'Foo: '.$string.PHP_EOL;
}
public functionprintPHP()
{
echo'PHP is great.'.PHP_EOL;
}
}
classBarextendsFoo
{
public functionprintItem($string)
{
echo'Bar: '.$string.PHP_EOL;
}
}
$foo= newFoo();
$bar= newBar();
$foo->printItem('baz');// 出力: 'Foo: baz'
$foo->printPHP();// 出力: 'PHP is great'
$bar->printItem('baz');// 出力: 'Bar: baz'
$bar->printPHP();// 出力: 'PHP is great'
?>PHP 8.1 より前のバージョンでは、 ほとんどの内部クラスやメソッドは戻り値の型を宣言していませんでしたし、 それらを継承する際にもあらゆる戻り値の型を指定することができていました。
PHP 8.1.0 以降では、 ほとんどの内部メソッドが、戻り値の型を "とりあえず" 宣言するようになりました。 この場合、それらを継承したメソッドの戻り値の型は、 親と互換性があるものにすべきです。 そうしない場合、推奨されない警告が発生します。 注意すべきなのは、明示的に戻り値の型を宣言していない場合でも、 シグネチャが一致していないとみなされ、 推奨されない警告が発生することです。
PHP のバージョン間の互換性を保ちたいがために、 戻り値の型を宣言できない場合、 アトリビュートReturnTypeWillChange を追加することで警告を抑止できます。
例2 戻り値の型を宣言せずにメソッドをオーバーライドする場合
<?php
classMyDateTimeextendsDateTime
{
public functionmodify(string $modifier) { returnfalse; }
}
// PHP 8.1.0 以降では、"Deprecated: Return type of MyDateTime::modify(string $modifier) should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice"
?>例3 間違った型を宣言してメソッドをオーバーライドする場合
<?php
classMyDateTimeextendsDateTime
{
public functionmodify(string $modifier): ?DateTime{ returnnull; }
}
// PHP 8.1.0 以降では、"Deprecated: Return type of MyDateTime::modify(string $modifier): ?DateTime should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice"
?>例4 間違った型を宣言してメソッドをオーバーライドする場合でも、警告を抑制する
<?php
classMyDateTimeextendsDateTime
{
/**
* @return DateTime|false
*/
#[\ReturnTypeWillChange]
public functionmodify(string $modifier) { returnfalse; }
}
// 警告は発生しません。
?>Here is some clarification about PHP inheritance – there is a lot of bad information on the net. PHP does support Multi-level inheritance. (I tested it using version 5.2.9). It does not support multiple inheritance. This means that you cannot have one class extend 2 other classes (see the extends keyword). However, you can have one class extend another, which extends another, and so on. Example:<?phpclassA{// more code here} classBextendsA{// more code here} classCextendsB{// more code here}$someObj= newA();// no problems$someOtherObj= newB();// no problems$lastObj= newC();// still no problems?>I think the best way for beginners to understand inheritance is through a real example so here is a simple example I can gave to you<?phpclassPerson{ public$name; protected$age; private$phone; public functiontalk(){//Do stuff here} protected functionwalk(){//Do stuff here} private functionswim(){//Do stuff here}}classTomextendsPerson{/*Since Tom class extends Person class this means that class Tom is a child class and class person is the parent class and child class will inherit all public and protected members(properties and methods) from the parent class*/ /*So class Tom will have these properties and methods*/ //public $name; //protected $age; //public function talk(){} //protected function walk(){} //but it will not inherit the private members //this is all what Object inheritance means}In case you have a public readonly property in a class you need to extend, adding other properties, this can be a way to do it:<?phpclassA{ public function__construct( public readonlyint $prop) {}}classBextendsA{ public function__construct(int $prop, public readonlyint $prop2) {parent::__construct($prop); }}?>The Idea that multiple inheritence is not supported is correct but with tratits this can be reviewed.for e.g.<?phptraitcustom{ public functionhello() { echo"hello"; }}traitcustom2{ public functionhello() { echo"hello2"; }}classinheritsCustom{ usecustom,custom2{custom2::helloinsteadofcustom; }}$obj= newinheritsCustom();$obj->hello();?>You can force a class to be strictly an inheritable class by using the "abstract" keyword. When you define a class with abstract, any attempt to instantiate a separate instance of it will result in a fatal error. This is useful for situations like a base class where it would be inherited by multiple child classes yet you want to restrict the ability to instantiate it by itself.Example........<?phpabstract classCheese{//can ONLY be inherited by another class}classCheddarextendsCheese{}$dinner= newCheese;//fatal error$lunch= newCheddar;//works!?>I was recently extending a PEAR class when I encountered a situation where I wanted to call a constructor two levels up the class hierarchy, ignoring the immediate parent. In such a case, you need to explicitly reference the class name using the :: operator.Fortunately, just like using the 'parent' keyword PHP correctly recognizes that you are calling the function from a protected context inside the object's class hierarchy.E.g:<?phpclassfoo{ public functionsomething() { echo__CLASS__;// foovar_dump($this); }}classfoo_barextendsfoo{ public functionsomething() { echo__CLASS__;// foo_barvar_dump($this); }}classfoo_bar_bazextendsfoo_bar{ public functionsomething() { echo__CLASS__;// foo_bar_bazvar_dump($this); } public functioncall() { echoself::something();// selfechoparent::something();// parentechofoo::something();// grandparent}}error_reporting(-1);$obj= newfoo_bar_baz();$obj->call();// Output similar to:// foo_bar_baz// object(foo_bar_baz)[1]// foo_bar// object(foo_bar_baz)[1]// foo// object(foo_bar_baz)[1]?>