
本文旨在解决php中尝试调用`protected __construct()`时遇到的错误。文章将深入探讨`protected`访问修饰符对构造函数的限制,并提供一种通过类继承来暴露公共构造函数的实用解决方案。此外,还将讨论构造函数可见性的最佳实践、工厂方法以及依赖注入等替代设计模式,以帮助开发者更有效地管理对象创建和类间协作。
在PHP中,protected 访问修饰符意味着一个成员(属性或方法)只能在其声明的类及其子类中被访问。当应用于 __construct() 构造函数时,它会阻止从类外部直接通过 new ClassName() 的方式实例化该类。这种设计通常用于以下场景:
当您尝试在不属于其继承链的另一个类中直接实例化一个具有 protected __construct() 的类时,PHP会抛出 Call to protected __construct() from context 错误,因为外部类不具备访问该保护构造函数的权限。
考虑以下两个PHP类,myClassA1 和 myClassA2:
<?php
// myClassA1.php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class myClassA1 extends Jsonable
{
protected $myPropertyA1; // 示例属性
protected function __construct(){
// 构造逻辑
$this->myPropertyA1 = "Data from A1";
}
public function getWhatINeed(){
return $this->myPropertyA1;
}
}<?php
// myClassA2.php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class myClassA2 extends Jsonable
{
protected $myPropertyA2; // 示例属性
protected $myClassA1Instance;
function __construct() {
parent::__construct();
$CI =& get_instance();
// 尝试加载并使用 myClassA1
$CI->load->model("myClassA1");
// 这里会尝试实例化 myClassA1,但其构造函数是 protected
$this->myClassA1Instance = $CI->myClassA1; // 假设CI加载后会赋值
// 接着尝试调用方法
if ($this->myClassA1Instance) {
$this->myClassA1Instance->getWhatINeed();
}
}
}在上述 myClassA2 的构造函数中,当CodeIgniter框架尝试通过 $CI->load->model("myClassA1") 来加载并实例化 myClassA1 时,由于 myClassA1 的 __construct() 方法被声明为 protected,而 myClassA2 并非 myClassA1 的子类,也无法直接访问其构造函数,因此会触发以下错误:
立即学习“PHP免费学习笔记(深入)”;
PHP Call to protected (from another model)::__construct() from context
这意味着 myClassA2 无法在当前上下文中直接创建 myClassA1 的实例。
如果无法修改原始类 myClassA1 的构造函数可见性,但又需要获取其实例,一种可行的策略是通过继承来创建一个新的类(可以是匿名类),该新类提供一个公共的构造函数,并在其中调用父类的 protected __construct()。由于子类可以访问父类的 protected 成员,这种方法是有效的。
以下是具体的实现示例:
<?php
// 假设这是在 myClassA2 或其他需要实例化 myClassA1 的地方
// ...
// 1. 创建一个匿名类,继承自 myClassA1
// 2. 在匿名类中定义一个公共的 __construct() 方法
// 3. 在公共构造函数中调用父类(myClassA1)的构造函数
$myClassA1PublicInstance = new class extends myClassA1 {
public function __construct()
{
parent::__construct(); // 调用 myClassA1 的 protected __construct()
}
};
// 现在可以通过 $myClassA1PublicInstance 正常访问 myClassA1 的公共方法
$data = $myClassA1PublicInstance->getWhatINeed();
echo $data; // 输出: Data from A1
// 如果是在 CodeIgniter 环境中,可以这样集成:
class myClassA2 extends Jsonable
{
protected $myPropertyA2;
protected $myClassA1Instance;
function __construct() {
parent::__construct();
$CI =& get_instance();
// 使用匿名类来实例化 myClassA1
$this->myClassA1Instance = new class extends myClassA1 {
public function __construct()
{
parent::__construct();
}
};
// 现在可以安全地调用 myClassA1 的公共方法
if ($this->myClassA1Instance) {
$result = $this->myClassA1Instance->getWhatINeed();
// ... 使用 result ...
}
}
}工作原理:
这种方法适用于当您无法修改原始类定义,但又需要绕过其构造函数访问限制的场景。
虽然上述继承方案可以解决特定问题,但在实际开发中,更推荐遵循以下最佳实践和设计模式:
构造函数可见性原则
工厂方法模式 当类的构造逻辑复杂,或者需要根据不同条件创建不同类型的对象时,可以采用工厂方法。如果 __construct() 是 protected 或 private,工厂方法就是获取实例的唯一途径。
class MyClassWithProtectedConstructor extends Jsonable
{
protected function __construct() { /* ... */ }
public static function createInstance(): self
{
// 可以在这里执行额外的逻辑或参数验证
return new self(); // 在类内部可以调用 protected __construct()
}
}
// 使用工厂方法获取实例
$instance = MyClassWithProtectedConstructor::createInstance();依赖注入 (Dependency Injection, DI) 在现代PHP框架(如CodeIgniter 4、Laravel、Symfony等)中,推荐使用依赖注入来管理类之间的依赖关系。而不是在类内部手动 load 或 new 另一个类,而是通过构造函数参数、setter方法或接口将依赖项“注入”到类中。
例如,在CodeIgniter 3中,$CI->load->model() 实际上是将模型实例挂载到 $CI 对象上。更好的做法是让框架处理依赖:
// 在 CodeIgniter 3 中,如果 myClassA1 确实是模型,且其构造函数是 public
class myClassA2 extends Jsonable
{
protected $myClassA1Instance;
function __construct() {
parent::__construct();
$CI =& get_instance();
$CI->load->model("myClassA1"); // 框架会实例化 myClassA1
$this->myClassA1Instance = $CI->myClassA1; // 获取实例
// ...
}
}如果 myClassA1 的构造函数确实需要 protected,并且您希望在 myClassA2 中使用它,那么您可能需要重新审视 myClassA1 的设计,或者通过 CodeIgniter 的服务容器(如果可用)来注册一个能够正确创建 myClassA1 实例的服务。
protected __construct() 的使用是PHP面向对象设计中的一个重要概念,它提供了对对象创建过程的精细控制。当遇到 Call to protected __construct() 错误时,首先应检查类的设计意图。如果无法修改原始类,通过创建一个继承类并提供公共构造函数是一种有效的运行时解决方案。然而,从长远来看,遵循构造函数可见性原则,并考虑采用工厂方法或依赖注入等设计模式,将有助于构建更健壮、可维护和可测试的应用程序。理解这些概念不仅能解决当前问题,更能提升您的PHP编程和架构设计能力。
以上就是PHP中protected __construct()的调用限制与扩展解决方案的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号