<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>潘锦的空间 &#187; 构造函数</title>
	<atom:link href="https://www.phppan.com/tag/%e6%9e%84%e9%80%a0%e5%87%bd%e6%95%b0/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sun, 10 May 2026 02:26:45 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>PHP源码阅读笔记二十七：PHP对构造方法的识别</title>
		<link>https://www.phppan.com/2010/11/php-source-27-construct/</link>
		<comments>https://www.phppan.com/2010/11/php-source-27-construct/#comments</comments>
		<pubDate>Mon, 01 Nov 2010 01:01:55 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHP源码]]></category>
		<category><![CDATA[构造函数]]></category>
		<category><![CDATA[类名函数]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=1077</guid>
		<description><![CDATA[PHP源码阅读笔记二十七：PHP对构造方法的识别 众所周知，由于历史原因，PHP之前是使用类名作为构造函数，在 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>PHP源码阅读笔记二十七：PHP对构造方法的识别<br />
众所周知，由于历史原因，PHP之前是使用类名作为构造函数，在PHP5中引入的新的构造函数__construct。为了实现向后兼容性，如果 PHP 5 在类中找不到 __construct() 函数，它就会尝试寻找旧式的构造函数，也就是和类同名的函数。因此唯一会产生兼容性问题的情况是：类中已有一个名为 __construct() 的方法，但它却又不是构造函数。<br />
有如下一段代码</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">class</span> Foo <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> Foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">new</span> Foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">die</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>此时，输出为：<br />
Fatal error: Call to private Foo::__construct() from invalid context<br />
此时，PHP识别出来的构造函数是__construct,因为是private，于是在外部调用出错。</p>
<p>好吧，我们从PHP的C源码中查找一下原因吧。<br />
从spl的扩展类中直接查找类的定义开始：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="code"><pre class="c" style="font-family:monospace;">spl_iterators.<span style="color: #202020;">c</span> <span style="color: #0000dd;">3228</span>行 REGISTER_SPL_STD_CLASS_EX<span style="color: #009900;">&#40;</span>IteratorIterator<span style="color: #339933;">,</span> spl_dual_it_new<span style="color: #339933;">,</span> spl_funcs_IteratorIterator<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">///spl_functions.h 31行</span>
<span style="color: #339933;">#define REGISTER_SPL_STD_CLASS_EX(class_name, obj_ctor, funcs) \
	spl_register_std_class(&amp;spl_ce_ ## class_name, # class_name, obj_ctor, funcs TSRMLS_CC);</span>
<span style="color: #666666; font-style: italic;">//spl_functions.c 41行</span>
PHPAPI <span style="color: #993333;">void</span> spl_register_std_class<span style="color: #009900;">&#40;</span>zend_class_entry <span style="color: #339933;">**</span> ppce<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span> class_name<span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span> obj_ctor<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> zend_function_entry <span style="color: #339933;">*</span> function_list TSRMLS_DC<span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//spl_functions.c 2235行</span>
ZEND_API zend_class_entry <span style="color: #339933;">*</span>zend_register_internal_class<span style="color: #009900;">&#40;</span>zend_class_entry <span style="color: #339933;">*</span>orig_class_entry TSRMLS_DC<span style="color: #009900;">&#41;</span> <span style="color: #808080; font-style: italic;">/* {{{ */</span>
<span style="color: #666666; font-style: italic;">//调用do_register_internal_class函数</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//zend_API.c 2169行</span>
<span style="color: #993333;">static</span> zend_class_entry <span style="color: #339933;">*</span>do_register_internal_class<span style="color: #009900;">&#40;</span>zend_class_entry <span style="color: #339933;">*</span>orig_class_entry<span style="color: #339933;">,</span> zend_uint ce_flags TSRMLS_DC<span style="color: #009900;">&#41;</span> <span style="color: #808080; font-style: italic;">/* {{{ */</span>
<span style="color: #666666; font-style: italic;">//调用</span>
zend_register_functions<span style="color: #009900;">&#40;</span>class_entry<span style="color: #339933;">,</span> class_entry<span style="color: #339933;">-&gt;</span>builtin_functions<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>class_entry<span style="color: #339933;">-&gt;</span>function_table<span style="color: #339933;">,</span> MODULE_PERSISTENT TSRMLS_CC<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//zend_API.c 1795行</span>
<span style="color: #808080; font-style: italic;">/* Look for ctor, dtor, clone
* If it's an old-style constructor, store it only if we don't have
* a constructor already.
*/</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>fname_len <span style="color: #339933;">==</span> class_name_len<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span><span style="color: #000066;">memcmp</span><span style="color: #009900;">&#40;</span>lowercase_name<span style="color: #339933;">,</span> lc_class_name<span style="color: #339933;">,</span> class_name_len<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span>ctor<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	ctor <span style="color: #339933;">=</span> reg_function<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>fname_len <span style="color: #339933;">==</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>ZEND_CONSTRUCTOR_FUNC_NAME<span style="color: #009900;">&#41;</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span><span style="color: #000066;">memcmp</span><span style="color: #009900;">&#40;</span>lowercase_name<span style="color: #339933;">,</span> ZEND_CONSTRUCTOR_FUNC_NAME<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>ZEND_CONSTRUCTOR_FUNC_NAME<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	ctor <span style="color: #339933;">=</span> reg_function<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> 
&nbsp;
scope<span style="color: #339933;">-&gt;</span>constructor <span style="color: #339933;">=</span> ctor<span style="color: #339933;">;</span>	<span style="color: #666666; font-style: italic;">//	在1961行 确认构造函数</span></pre></td></tr></table></div>

<p>以上代码为php5.3.0版本<br />
从以上跟踪流程来看，程序在注册所有函数时，如果存在__construct(即ZEND_CONSTRUCTOR_FUNC_NAME)时，会覆盖class_name(类名)的构造函数，使其作为常规的成员函数存在。如下所示代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">class</span> Foo <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> Foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Foo'</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'__construct'</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000088;">$foo</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$foo</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Foo</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>对于在前面的示例中的报错，我们可以在<br />
zend/zend_object_handlers.c 1057行<br />
ZEND_API union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC)<br />
找到出处。</p>
<p>&#8211;EOF-</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2010/11/php-source-27-construct/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
