当前位置:  开发笔记 > 编程语言 > 正文

面向对象中PHP构造方法的识别

众所周知,由于历史原因,PHP之前是使用类名作为构造函数,在PHP5中引入的新的构造函数__construct。为了实现向后兼容性,如果PHP5在类中找不到__construct()函数,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。因此唯一会产生兼容性问题的情">

  众所周知,由于历史原因,PHP之前是使用类名作为构造函数,在PHP 5中引入的新的构造函数__construct。为了实现向后兼容性,如果PHP 5在类中找不到 __construct() 函数,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。

  因此唯一会产生兼容性问题的情况是:类中已有一个名为 __construct() 的方法,但它却又不是构造函数。有如下一段代码:

 

  1. class Foo {    
  2.      
  3.     public function Foo() {    
  4.      
  5.     }    
  6.      
  7.     private function __construct() {    
  8.      
  9.     }    
  10. }    
  11.      
  12. new Foo();    
  13. die();   

  此时,输出为:

  Fatal error: Call to private Foo::__construct() from invalid context

  此时,PHP识别出来的构造函数是__construct,因为是private,于是在外部调用出错。好吧,我们从PHP的C源码中查找一下原因吧。从SQL的扩展类中直接查找类的定义开始:

 

  1. spl_iterators.c 3228行 REGISTER_SPL_STD_CLASS_EX(IteratorIterator, spl_dual_it_new, spl_funcs_IteratorIterator);    
  2. ///spl_functions.h 31行    
  3. #define REGISTER_SPL_STD_CLASS_EX(class_name, obj_ctor, funcs) \    
  4.  spl_register_std_class(&spl_ce_ ## class_name, # class_name, obj_ctor, funcs TSRMLS_CC);    
  5. //spl_functions.c 41行    
  6. PHPAPI void spl_register_std_class(zend_class_entry ** ppce, char * class_name, void * obj_ctor, const zend_function_entry * function_list TSRMLS_DC)    
  7.      
  8. //spl_functions.c 2235行    
  9. ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *orig_class_entry TSRMLS_DC) /* {{{ */    
  10. //调用do_register_internal_class函数    
  11.      
  12. //zend_API.c 2169行    
  13. static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class_entry, zend_uint ce_flags TSRMLS_DC) /* {{{ */    
  14. //调用    
  15. zend_register_functions(class_entry, class_entry->builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);    
  16.      
  17. //zend_API.c 1795行    
  18. /* Look for ctor, dtor, clone    
  19. * If it's an old-style constructor, store it only if we don't have    
  20. * a constructor already.    
  21. */    
  22. if ((fname_len == class_name_len) && !memcmp(lowercase_name, lc_class_name, class_name_len+1) && !ctor) {    
  23.  ctor = reg_function;    
  24. else if ((fname_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME))) {    
  25.  ctor = reg_function;    
  26. }     
  27.      
  28. scope->constructor = ctor; //在1961行 确认构造函数  

  以上代码为PHP 5.3.0版本

  从以上跟踪流程来看,程序在注册所有函数时,如果存在__construct(即ZEND_CONSTRUCTOR_FUNC_NAME)时,会覆盖class_name(类名)的构造函数,使其作为常规的成员函数存在。如下所示代码:

 

  1. php   
  2. class Foo {    
  3.      
  4.     public function Foo() {    
  5.         echo 'Foo';    
  6.     }    
  7.      
  8.     public function __construct() {    
  9.         echo '__construct';    
  10.     }    
  11. }    
  12.      
  13. $foo = new Foo();    
  14. $foo->Foo();  

  对于在前面的示例中的报错,我们可以在zend/zend_object_handlers.c 1057行ZEND_API union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC)找到出处。


推荐阅读
  • 本文详细介绍了如何在PHP中删除数组中的指定元素、第一个元素和最后一个元素,并提供了具体的代码示例和相关函数的使用说明。 ... [详细]
  • 本文详细解析了汉字‘犐’的基本字义及其在古代文献中的应用,旨在为读者提供全面而深入的理解。 ... [详细]
  • 本文探讨如何配置 Nginx 以将传入请求反向代理到运行在本地绑定端口上的 Docker 容器,并解决常见的路径重定向问题。 ... [详细]
  • 12月16日JavaScript变量、函数、流程、循环等***线上九期班
    12月16日JavaScript变量、函数、流程、循环等***线上九期班 ... [详细]
  • 卫青与汉武帝的君臣关系及家族命运
    本文探讨了卫青与汉武帝之间的特殊关系,以及卫青去世后其家族的命运。卫青不仅是汉武帝的重要将领,还通过婚姻关系成为皇亲国戚。然而,卫青去世后,其家族并未立即遭到灭顶之灾,而是逐渐因政治风波受到牵连。 ... [详细]
  • 如何在AE中创建裂变式加载动画
    本文将详细介绍如何使用Adobe After Effects (AE) 制作一个裂变式加载动画。通过简单的步骤,您可以轻松创建出引人注目的转圈式加载效果。 ... [详细]
  • 本文详细介绍了如何在PHP中进行数组删除、清空等操作,并提供了在Visual Studio Code中创建PHP文件的步骤。 ... [详细]
  • 探索新一代API文档工具,告别Swagger的繁琐
    对于后端开发者而言,编写和维护API文档既繁琐又不可或缺。本文将介绍一款全新的API文档工具,帮助团队更高效地协作,简化API文档生成流程。 ... [详细]
  • 实现自定义组件的多值v-model双向绑定
    探讨如何在自定义组件中实现多个输入框与父组件数据的动态双向绑定,确保组件内部多个值的变化能实时反映到父组件的数据中。 ... [详细]
  • 本文深入解析宋代诗人苏轼的《催试官考较戏作》,探讨其诗中的意境、意象及艺术特色,同时提供详细的译文,帮助读者更好地理解这首经典之作。 ... [详细]
  • 本文详细介绍了在不同操作系统中查找和设置网卡的方法,涵盖了Windows系统的具体步骤,并提供了关于网卡位置、无线网络设置及常见问题的解答。 ... [详细]
  • 使用Nginx反向代理实现多域名端口映射
    本文介绍如何通过配置本地hosts文件和Nginx反向代理,实现多个虚拟域名的端口映射,使用户可以通过标准HTTP端口80访问不同后端服务。 ... [详细]
  • 本文探讨了在构建应用程序时,如何对不同类型的数据进行结构化设计。主要分为三类:全局配置、用户个人设置和用户关系链。每种类型的数据都有其独特的用途和应用场景,合理规划这些数据结构有助于提升用户体验和系统的可维护性。 ... [详细]
  • 历经三十年的开发,Mathematica 已成为技术计算领域的标杆,为全球的技术创新者、教育工作者、学生及其他用户提供了一个领先的计算平台。最新版本 Mathematica 12.3.1 增加了多项核心语言、数学计算、可视化和图形处理的新功能。 ... [详细]
  • Linux中的yum安装软件
    yum俗称大黄狗作用:解决安装软件包的依赖关系当安装依赖关系的软件包时,会将依赖的软件包一起安装。本地yum:需要yum源,光驱挂载。yum源:(刚开始查看yum源中的内容就是上图 ... [详细]
author-avatar
IvyShao520
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有