本文深入探讨了PHP中尝试从外部上下文调用受保护(protected)构造函数时遇到的'Call to protected ::__construct()'错误。我们将解释访问修饰符的工作原理,并提供两种主要解决方案:通过继承创建公共构造函数,以及重新评估构造函数本身的访问权限。旨在帮助开发者理解并正确处理此类PHP设计模式问题。
在 PHP 中,类的属性和方法可以通过访问修饰符(public、protected、private)来控制其可见性和可访问性。构造函数 __construct() 也不例外。
当一个类(例如 myClassA2)尝试实例化另一个类(例如 myClassA1),而 myClassA1 的构造函数被声明为 protected 时,就会触发 Call to protected ::__construct() from context 错误。这是因为 myClassA2 并非 myClassA1 的子类,因此没有权限直接访问其受保护的构造函数。
考虑以下两个类结构:
data = "数据来自 A1";
// 模拟一些初始化操作
}
public function getWhatINeed()
{
return $this->data;
}
}
// myClassA2.php
class myClassA2
{
protected $myClassA1Instance;
function __construct()
{
// 假设这里尝试加载并实例化 myClassA1
// 在某些框架中,例如CodeIgniter的load->model(),可能会尝试直接实例化
// 如果 myClassA1 的构造函数是 protected,这里会失败
// $this->myClassA1Instance = new myClassA1(); // 模拟直接实例化,会导致错误
// 错误示例:直接尝试访问或实例化一个受保护构造函数的类
// $this->myClassA1Instance->getWhatINeed();
}
}在上述情境中,如果 myClassA2 内部或通过框架机制尝试直接实例化 myClassA1(例如通过 new myClassA1()),由于 myClassA1::__construct() 是 protected 的,PHP 会抛出错误,因为它不允许从 myClassA2 的上下文直接调用 myClassA1 的受保护构造函数。
解决此问题的一种常见且符合设计模式的方法是,创建一个新的类来扩展原始类,并在新类中定义一个 public 的构造函数。这个 public 构造函数可以安全地调用父类的 protected 构造函数。
data = "数据来自 A1";
}
public function getWhatINeed()
{
return $this->data;
}
}
// 解决方案:创建一个匿名子类或具名子类
// 方式一:使用匿名类(PHP 7+)
$instanceOfA1 = new class extends myClassA1 {
public function __construct()
{
echo "匿名子类的 public 构造函数被调用。\n";
parent::__construct(); // 调用父类 myClassA1 的 protected 构造函数
}
};
echo $instanceOfA1->getWhatINeed() . "\n"; // 输出:数据来自 A1
// 方式二:使用具名子类(更常见和推荐的做法)
class M
yPublicClassA1 extends myClassA1 {
public function __construct() {
echo "MyPublicClassA1 的 public 构造函数被调用。\n";
parent::__construct(); // 调用父类 myClassA1 的 protected 构造函数
}
}
$anotherInstanceOfA1 = new MyPublicClassA1();
echo $anotherInstanceOfA1->getWhatINeed() . "\n"; // 输出:数据来自 A1
?>工作原理: 由于 MyPublicClassA1 (或匿名子类) 是 myClassA1 的子类,它拥有访问 myClassA1 的 protected 成员(包括 __construct())的权限。因此,在 MyPublicClassA1 的 public __construct() 中调用 parent::__construct() 是完全合法的。通过这种方式,我们创建了一个可以被外部直接实例化的类,同时仍然遵守了 myClassA1 原始设计中对其构造函数的访问限制。
在某些情况下,__construct() 被声明为 protected 可能并非最佳选择,或者可能只是一个误解。在决定使用 protected 或 private 构造函数之前,请考虑以下设计模式:
工厂模式 (Factory Pattern): 当一个类的创建过程比较复杂,或者需要根据不同条件创建不同类型的对象时,可以使用工厂模式。工厂方法通常是静态的,并负责实例化对象。在这种情况下,构造函数可以是 protected 或 private。
class Product {
protected function __construct() { /* ... */ }
public static function create(string $type): Product {
// 根据类型创建具体产品
// ...
return new static(); // 假设这里简化,实际可能创建子类
}
}
// 使用工厂方法创建实例
$product = Product::create('typeA');单例模式 (Singleton Pattern): 确保一个类只有一个实例,并提供一个全局访问点。在这种模式下,构造函数必须是 private 的,以防止外部直接实例化。
class Singleton {
private static $instance;
private function __construct() { /* ... */ } // 私有构造函数
public static function getInstance(): Singleton {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
// 使用单例模式获取实例
$instance = Singleton::getInstance();抽象类 (Abstract Class): 抽象类不能直接实例化,它们旨在被其他类继承。因此,抽象类的构造函数可以是 public、protected 或 private。如果它有 protected 构造函数,意味着只有其子类才能在自己的构造函数中调用它。
何时将构造函数设为 public? 如果一个类旨在被直接实例化,并且其初始化逻辑不需要特殊控制或外部辅助,那么将其构造函数设为 public 是最直接和常见的做法。在大多数业务逻辑类中,public __construct() 是默认且推荐的选择。
建议: 在遇到 Call to protected ::__construct() 错误时,首先审视 myClassA1 的设计意图:
Call to protected ::__construct() from context 错误是 PHP 访问修饰符规则的直接体现。解决此问题主要有两种策略:
选择哪种方案取决于你的具体设计需求和对代码可维护性的考量。在大多数情况下,如果一个类需要被广泛使用和实例化,public __construct() 是最直接和易于理解的选择。如果存在更复杂的创建逻辑或需要限制实例数量,则应考虑使用工厂方法或单例模式。
# php
# 父类
# 子类
# 构造函数
# 继承
# 接口
# class
# public
# private
# protected
# 对象
# 类中
# 将其
# 自己的
# 修饰符
# 创建一个
# 设为
# 并在
# 抽象类
# 工作原理
相关文章:
如何注册花生壳免费域名并搭建个人网站?
建站VPS能否同时实现高效与安全翻墙?
如何在建站宝盒中设置产品搜索功能?
教程网站设计制作软件,怎么创建自己的一个网站?
网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?
,网页ppt怎么弄成自己的ppt?
建站之星CMS五站合一模板配置与SEO优化指南
深圳防火门网站制作公司,深圳中天明防火门怎么编码?
云南网站制作公司有哪些,云南最好的招聘网站是哪个?
广州建站公司哪家好?十大优质服务商推荐
如何通过西部建站助手安装IIS服务器?
整人网站在线制作软件,整蛊网站退不出去必须要打我是白痴才能出去?
如何用PHP快速搭建高效网站?分步指南
企业网站制作费用多少,企业网站空间一般需要多大,费用是多少?
非常酷的网站设计制作软件,酷培ai教育官方网站?
如何基于云服务器快速搭建网站及云盘系统?
如何通过虚拟主机快速完成网站搭建?
Swift开发中switch语句值绑定模式
Python多线程使用规范_线程安全解析【教程】
制作门户网站的参考文献在哪,小说网站怎么建立?
如何生成腾讯云建站专用兑换码?
制作网站怎么制作,*游戏网站怎么搭建?
如何用5美元大硬盘VPS安全高效搭建个人网站?
网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?
C#如何序列化对象为XML XmlSerializer用法
独立制作一个网站多少钱,建立网站需要花多少钱?
如何在阿里云完成域名注册与建站?
建站之星3.0如何解决常见操作问题?
公司网站制作费用多少,为公司建立一个网站需要哪些费用?
电商网站制作价格怎么算,网上拍卖流程以及规则?
北京的网站制作公司有哪些,哪个视频网站最好?
制作网站的网址是什么,请问后缀为.com和.com.cn还有.cn的这三种网站是分别是什么类型的网站?
北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?
建站168自助建站系统:快速模板定制与SEO优化指南
高防服务器租用首荐平台,企业级优惠套餐快速部署
七夕网站制作视频,七夕大促活动怎么报名?
网站制作说明怎么写,简述网页设计的流程并说明原因?
专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?
长沙做网站要多少钱,长沙国安网络怎么样?
香港服务器网站推广:SEO优化与外贸独立站搭建策略
如何用PHP工具快速搭建高效网站?
油猴 教程,油猴搜脚本为什么会网页无法显示?
网站制作价目表怎么做,珍爱网婚介费用多少?
无锡制作网站公司有哪些,无锡优八网络科技有限公司介绍?
如何登录建站主机?访问步骤全解析
高端云建站费用究竟需要多少预算?
电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?
rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted
交易网站制作流程,我想开通一个网站,注册一个交易网址,需要那些手续?
手机网站制作与建设方案,手机网站如何建设?
*请认真填写需求信息,我们会在24小时内与您取得联系。