PHP子类必须显式调用parent::__construct()才能执行父类初始化逻辑,否则属性、依赖注入等均被跳过;多态生效依赖类型提示与运行时真实类型共同作用。

PHP中子类怎么正确调用父类构造函数
不显式调用 parent::__construct(),父类初始化逻辑就直接跳过了——哪怕你只重写了子类的 __construct(),父类里声明的属性、依赖注入、资源初始化全都不会执行。
- 子类有
__construct()时,PHP 不会自动调用父类同名方法,必须手动写parent::__construct(...) - 参数要严格匹配父类构造函数签名;如果父类构造函数带必填参数,子类必须传,不能靠默认值“蒙混过关”
- 调用位置建议放在子类构造函数开头(除非你明确需要先做些前置判断再初始化父类)
- 如果父类构造函数抛异常,子类里没加
try/catch,整个实例化就失败,这点在依赖容器自动解析时容易被忽略
示例:
class DatabaseConnection {<br> public function __construct(string $dsn) {<br> // 连接初始化逻辑<br> }<br>}<br><br>class MySQLConnection extends DatabaseConnection {<br> public function __construct(string $host, string $dbname) {<br> $dsn = "mysql:host={$host};dbname={$dbname}";<br> parent::__construct($dsn); // 必须这句,否则父类没执行<br> }<br>}
PHP多态靠什么实际生效
不是靠“写了 extends”或“用了接口”,而是靠类型提示 + 运行时对象真实类型共同起作用。没有类型约束的函数参数,根本谈不上多态。
- 只有在函数/方法参数声明了父类或接口类型(如
function handle(Animal $a)),传入子类实例时,才能触发多态行为 - 如果参数是
mixed、object或无类型声明,PHP 就当普通对象处理,不会校验是否符合继承契约 - 返回类型声明(如
function create(): Animal)也能参与多态,但调用方仍需按声明类型使用,否则 IDE 和静态分析工具可能报错 - 注意
self和static的区别:用self::会绑定到当前类,破坏多态;static::才支持后期静态绑定(Late Static Binding)
重写方法时怎么避免破坏LSP(里氏替换原则)
表面上方法名一样、参数对得上,不代表能安全替换。PHP 不强制检查契约,全靠开发者自己盯住行为一致性。
立即学习“PHP免费学习笔记(深入)”;
- 子类方法不能缩小父类方法的可见性(比如父类
public function save(),子类不能改成protected function save()) - 子类不能抛出父类没声明的新异常类型,否则调用方的
catch (InvalidArgumentException $e)会漏掉子类抛的ConnectionException - 返回值类型必须兼容:若父类返回
array,子类可返回array|string(联合类型),但不能只返回string(除非父类声明是mixed) - 不要在子类重写方法里偷偷改变副作用范围——比如父类
delete()只删数据库记录,子类额外发了邮件,上游代码就可能因“意外通知”出问题
trait和继承混用时多态还成立吗
trait 本身不参与继承链,也不提供类型,所以它不能替代父类或接口来支撑多态。但它可以被多个类复用,间接影响多态行为的一致性。
- trait 中的方法如果被子类直接使用,且该子类又实现了某接口或继承了某父类,那它仍然算作该类的一部分,多态照常工作
- 但 trait 无法声明抽象方法或类型约束,也不能被
instanceof检测——你不能写$obj instanceof MyTrait - 如果多个 trait 提供同名方法,必须用
insteadof明确排除冲突,否则 fatal error;这个过程发生在编译期,不影响运行时多态逻辑,但容易掩盖设计意图 - 常见坑:把本该抽成接口的行为塞进 trait,结果不同类虽然用了同一段逻辑,却无法被统一类型提示接收,导致多态断在第一关
真正决定多态能否落地的,从来不是语法能不能写,而是类型声明有没有立住、行为有没有守约。这两个地方松动一点,后面所有“面向对象”的设计都容易变成空架子。



















