php-srcのコードリーディングした内容をコツコツ残すテスト。その14
引き続きclass。今日は継承
<?php
class Base
{
public function call()
{
echo 123;
}
}
class Hoge extends Base
{
}
(new Hoge)->call();
opcode
$_main:
; (lines=5, args=0, vars=0, tmps=3)
; (before optimizer)
; /path/to/14.php:1-18
; return [] RANGE[0..0]
0000 V0 = NEW 0 string("Hoge")
0001 DO_FCALL
0002 INIT_METHOD_CALL 0 V0 string("call")
0003 DO_FCALL
0004 RETURN int(1)
LIVE RANGES:
0: 0001 - 0002 (new)
Base::call:
; (lines=2, args=0, vars=0, tmps=0)
; (before optimizer)
; /path/to/14.php:7-10
; return [] RANGE[0..0]
0000 ECHO int(123)
0001 RETURN null
extendsが定義されていると、 ce->parent_name
にスーパークラスの名前がセットされる。
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7721-L7724
parent_name
を使って EG(class_table)
からzend_class_entryを引いてくる。
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7764-L7765
zend_do_inheritance_ex()
で継承の設定が色々行われる
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1456-L1458
子クラスのデフォルトプロパティをセット
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1443-L1454
親クラスのデフォルトプロパティをセット
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1474-L1483
offsetの位置を調整
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1541:L1541
parentにも同じ名前のプロパティがあればチェックするだけ、 parentにあってchildになければ追加する、といったことをやっている
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1551-L1553
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1225-L1282
constructorと言いつつ全マジックメソッドを良い感じにオーバーライド
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L112:L112
同名のデフォルトプロパティはparent側にマージ。childの値をparentに代入し、child側をUNDEFする。
child_info->offsetにparent_info->offsetを代入することで、parent側に向くようにしている。
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1258-L1260
private, public, abstract
メソッドの場合は do_inheritance_check_on_method_ex()
でアクセス修飾子のチェックを行っている
parentがfinalの場合はエラー
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1051-L1058
child staticの設定状態とparent staticの設定状態が異なる場合はエラー
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1063-L1076
↓は以下のようなコードの場合にエラーにしている
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1079-L1086
<?php
class Base
{
public function call() {}
}
abstract class Hoge extends Base
{
public abstract function call();
}
childがprivate、parentがpublicといった感じでchildがアクセス制限を狭める場合にエラー
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1122-L1130
プロパティの場合
parentのstaticとchildのstaticの設定状態が変わる場合はエラー
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1236:L1236
parentとchildのreadonlyの設定状態が変わる場合はエラー
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1241
childがprivate、parentがpublicといった感じでchildがアクセス制限を狭める場合にエラー
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L1250
abstractのチェック
abstractな関数を持っていたり、abstractな関数を持つクラスを継承している場合、zend_verify_abstract_class()
でチェックされる
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L3050-L3052
abstractな関数を持っていて(継承して実装している場合は除く)、abstractクラスではない場合エラーになる。
https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_inheritance.c#L2313-L2344