<?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/%e7%94%a8%e6%88%b7%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>Sat, 25 Apr 2026 00:56:17 +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内核中用户函数、内部函数和中间代码的转换</title>
		<link>https://www.phppan.com/2011/08/function-op-array/</link>
		<comments>https://www.phppan.com/2011/08/function-op-array/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 01:17:59 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHP内核]]></category>
		<category><![CDATA[深入理解PHP内核]]></category>
		<category><![CDATA[用户函数]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=1439</guid>
		<description><![CDATA[昨天和一朋友在邮件中讨论这样一个问题：zend_internal_function，zend_function [&#8230;]]]></description>
				<content:encoded><![CDATA[<p style="text-indent: 2em;">昨天和一朋友在邮件中讨论这样一个问题：zend_internal_function，zend_function，zend_op_array这三种结构是可以相互转化的，这三者的转化是如何进行的呢？ 以此文，总结。</p>
<p style="text-indent: 2em;">在函数调用的执行代码中我们会看到这样一些强制转换：</p>
<pre style="background-color: #333333; color: #ffffff; font: normal normal normal 13px/normal 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Courier New', monospace; overflow-x: auto; overflow-y: auto; padding: 10px;">EX<span style="color: #ffffff;">(</span>function_state<span style="color: #ffffff;">)</span>.<span style="color: #cc7833;">function</span> <span style="color: #e0882f;">=</span> <span style="color: #ffffff;">(</span>zend_function <span style="color: #e0882f;">*</span><span style="color: #ffffff;">)</span> op_array<span style="color: #e0882f;">;</span>

或者：

EG<span style="color: #ffffff;">(</span>active_op_array<span style="color: #ffffff;">)</span> <span style="color: #e0882f;">=</span> <span style="color: #ffffff;">(</span>zend_op_array <span style="color: #e0882f;">*</span><span style="color: #ffffff;">)</span> EX<span style="color: #ffffff;">(</span>function_state<span style="color: #ffffff;">)</span>.<span style="color: #cc7833;">function</span><span style="color: #e0882f;">;</span></pre>
<p style="text-indent: 2em;">这种不同结构间的强制转换是如何进行的呢？</p>
<p style="text-indent: 2em;">首先我们来看zend_function的结构，在Zend/zend_compile.h文件中，其定义如下：</p>
<pre style="background-color: #333333; color: #ffffff; font: normal normal normal 13px/normal 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Courier New', monospace; overflow-x: auto; overflow-y: auto; padding: 10px;"><span style="color: #1299da;">typedef</span> <span style="color: #1299da;">union</span> _zend_function <span style="color: #ffffff;">{</span>
    zend_uchar type<span style="color: #e0882f;">;</span>    <span style="color: #bd48b3; font-style: italic;">/* MUST be the first element of this struct! */</span>

    <span style="color: #1299da;">struct</span> <span style="color: #ffffff;">{</span>
        zend_uchar type<span style="color: #e0882f;">;</span>  <span style="color: #bd48b3; font-style: italic;">/* never used */</span>
        <span style="color: #1299da;">char</span> <span style="color: #e0882f;">*</span>function_name<span style="color: #e0882f;">;</span>
        zend_class_entry <span style="color: #e0882f;">*</span>scope<span style="color: #e0882f;">;</span>
        zend_uint fn_flags<span style="color: #e0882f;">;</span>
        <span style="color: #1299da;">union</span> _zend_function <span style="color: #e0882f;">*</span>prototype<span style="color: #e0882f;">;</span>
        zend_uint num_args<span style="color: #e0882f;">;</span>
        zend_uint required_num_args<span style="color: #e0882f;">;</span>
        zend_arg_info <span style="color: #e0882f;">*</span>arg_info<span style="color: #e0882f;">;</span>
        zend_bool pass_rest_by_reference<span style="color: #e0882f;">;</span>
        <span style="color: #1299da;">unsigned</span> <span style="color: #1299da;">char</span> return_reference<span style="color: #e0882f;">;</span>
    <span style="color: #ffffff;">}</span> common<span style="color: #e0882f;">;</span>

    zend_op_array op_array<span style="color: #e0882f;">;</span>
    zend_internal_function internal_function<span style="color: #e0882f;">;</span>
<span style="color: #ffffff;">}</span> zend_function<span style="color: #e0882f;">;</span></pre>
<p style="text-indent: 2em;">这是一个联合体，我们来温习一下联合体的一些特性。 联合体的所有成员变量共享内存中的一块内存，在某个时刻只能有一个成员使用这块内存， 并且当使用某一个成员时，其仅能按照它的类型和内存大小修改对应的内存空间。 我们来看看一个例子：</p>
<pre style="background-color: #333333; color: #ffffff; font: normal normal normal 13px/normal 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Courier New', monospace; overflow-x: auto; overflow-y: auto; padding: 10px;"><span style="color: #bd48b3; font-style: italic;">#include &lt;stdio.h&gt;</span>
<span style="color: #bd48b3; font-style: italic;">#include &lt;stdlib.h&gt;</span>

<span style="color: #1299da;">int</span> main<span style="color: #ffffff;">(</span><span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
    <span style="color: #1299da;">typedef</span>  <span style="color: #1299da;">union</span> _utype
    <span style="color: #ffffff;">{</span>
        <span style="color: #1299da;">int</span> i<span style="color: #e0882f;">;</span>
        <span style="color: #1299da;">char</span> ch<span style="color: #ffffff;">[</span><span style="color: #1299da;">2</span><span style="color: #ffffff;">]</span><span style="color: #e0882f;">;</span>
    <span style="color: #ffffff;">}</span> utype<span style="color: #e0882f;">;</span> 

    utype a<span style="color: #e0882f;">;</span>

    a.<span style="color: #ffffff;">i</span> <span style="color: #e0882f;">=</span> <span style="color: #1299da;">10</span><span style="color: #e0882f;">;</span>
    a.<span style="color: #ffffff;">ch</span><span style="color: #ffffff;">[</span><span style="color: #1299da;">0</span><span style="color: #ffffff;">]</span> <span style="color: #e0882f;">=</span> <span style="color: #99ff00;">'1'</span><span style="color: #e0882f;">;</span>
    a.<span style="color: #ffffff;">ch</span><span style="color: #ffffff;">[</span><span style="color: #1299da;">1</span><span style="color: #ffffff;">]</span> <span style="color: #e0882f;">=</span> <span style="color: #99ff00;">'1'</span><span style="color: #e0882f;">;</span>

    <a style="color: #1299da; text-decoration: none;" href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #e2392d;">printf</span></a><span style="color: #ffffff;">(</span><span style="color: #99ff00;">"a.i= %d a.ch=%s"</span><span style="color: #e0882f;">,</span>a.<span style="color: #ffffff;">i</span><span style="color: #e0882f;">,</span> a.<span style="color: #ffffff;">ch</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>
    getchar<span style="color: #ffffff;">(</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>

    <span style="color: #ff8400;">return</span> <span style="color: #ffffff;">(</span>EXIT_SUCCESS<span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>
<span style="color: #ffffff;">}</span></pre>
<p style="text-indent: 2em;">程序输出：a.i= 12593 a.ch=11 当修改ch的值时，它会依据自己的规则覆盖i字段对应的内存空间。 &#8217;1&#8242;对应的ASCII码值是49，二进制为00110001，当ch字段的两个元素都为&#8217;1&#8242;时，此时内存中存储的二进制为 00110001 00110001 转成十进制，其值为12593。</p>
<p style="text-indent: 2em;">回过头来看zend_function的结构，它也是一个联合体，第一个字段为type， 在common中第一个字段也为type，并且其后面注释为/* Never used*/，此处的type字段的作用就是为第一个字段的type留下内存空间。并且不让其它字段干扰了第一个字段。 我们再看zend_op_array的结构：</p>
<pre style="background-color: #333333; color: #ffffff; font: normal normal normal 13px/normal 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Courier New', monospace; overflow-x: auto; overflow-y: auto; padding: 10px;"><span style="color: #1299da;">struct</span> _zend_op_array <span style="color: #ffffff;">{</span>
    <span style="color: #bd48b3; font-style: italic;">/* Common elements */</span>
    zend_uchar type<span style="color: #e0882f;">;</span>
    <span style="color: #1299da;">char</span> <span style="color: #e0882f;">*</span>function_name<span style="color: #e0882f;">;</span>
    zend_class_entry <span style="color: #e0882f;">*</span>scope<span style="color: #e0882f;">;</span>
    zend_uint fn_flags<span style="color: #e0882f;">;</span>
    <span style="color: #1299da;">union</span> _zend_function <span style="color: #e0882f;">*</span>prototype<span style="color: #e0882f;">;</span>
    zend_uint num_args<span style="color: #e0882f;">;</span>
    zend_uint required_num_args<span style="color: #e0882f;">;</span>
    zend_arg_info <span style="color: #e0882f;">*</span>arg_info<span style="color: #e0882f;">;</span>
    zend_bool pass_rest_by_reference<span style="color: #e0882f;">;</span>
    <span style="color: #1299da;">unsigned</span> <span style="color: #1299da;">char</span> return_reference<span style="color: #e0882f;">;</span>
    <span style="color: #bd48b3; font-style: italic;">/* END of common elements */</span>

    zend_bool done_pass_two<span style="color: #e0882f;">;</span>
    ....<span style="color: #bc9458; font-style: italic;">//  其它字段</span>
<span style="color: #ffffff;">}</span></pre>
<p style="text-indent: 2em;">这里的字段集和common的一样，于是在将zend_function转化成zend_op_array时并不会产生影响，这种转变是双向的。</p>
<p style="text-indent: 2em;">再看zend_internal_function的结构：</p>
<pre style="background-color: #333333; color: #ffffff; font: normal normal normal 13px/normal 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Courier New', monospace; overflow-x: auto; overflow-y: auto; padding: 10px;"><span style="color: #1299da;">typedef</span> <span style="color: #1299da;">struct</span> _zend_internal_function <span style="color: #ffffff;">{</span>
    <span style="color: #bd48b3; font-style: italic;">/* Common elements */</span>
    zend_uchar type<span style="color: #e0882f;">;</span>
    <span style="color: #1299da;">char</span> <span style="color: #e0882f;">*</span> function_name<span style="color: #e0882f;">;</span>
    zend_class_entry <span style="color: #e0882f;">*</span>scope<span style="color: #e0882f;">;</span>
    zend_uint fn_flags<span style="color: #e0882f;">;</span>
    <span style="color: #1299da;">union</span> _zend_function <span style="color: #e0882f;">*</span>prototype<span style="color: #e0882f;">;</span>
    zend_uint num_args<span style="color: #e0882f;">;</span>
    zend_uint required_num_args<span style="color: #e0882f;">;</span>
    zend_arg_info <span style="color: #e0882f;">*</span>arg_info<span style="color: #e0882f;">;</span>
    zend_bool pass_rest_by_reference<span style="color: #e0882f;">;</span>
    <span style="color: #1299da;">unsigned</span> <span style="color: #1299da;">char</span> return_reference<span style="color: #e0882f;">;</span>
    <span style="color: #bd48b3; font-style: italic;">/* END of common elements */</span>

    <span style="color: #1299da;">void</span> <span style="color: #ffffff;">(</span><span style="color: #e0882f;">*</span>handler<span style="color: #ffffff;">)</span><span style="color: #ffffff;">(</span>INTERNAL_FUNCTION_PARAMETERS<span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>
    <span style="color: #1299da;">struct</span> _zend_module_entry <span style="color: #e0882f;">*</span>module<span style="color: #e0882f;">;</span>
<span style="color: #ffffff;">}</span> zend_internal_function<span style="color: #e0882f;">;</span></pre>
<p style="text-indent: 2em;">同样存在公共元素，和common结构体一样，我们可以将zend_function结构强制转化成zend_internal_function结构，并且这种转变是双向的。</p>
<p style="text-indent: 2em;">总的来说zend_internal_function，zend_function，zend_op_array这三种结构在一定程序上存在公共的元素， 于是这些元素以联合体的形式共享内存，并且在执行过程中对于一个函数，这三种结构对应的字段在值上都是一样的， 于是可以在一些结构间发生完美的强制类型转换。 可以转换的列表如下：</p>
<ul>
<li>zend_function可以与zend_op_array互换</li>
<li>zend_function可以与zend_internal_function互换</li>
</ul>
<p style="text-indent: 2em;">但是一个zend_op_array结构转换成zend_function是不能再次转变成zend_internal_function结构的，反之亦然。</p>
<p style="text-indent: 2em;">其实zend_function就是一个混合的数据结构，这种结构在一定程序上节省了内存空间。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2011/08/function-op-array/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
