<?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/%e5%ad%97%e7%ac%a6%e4%b8%b2/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sun, 12 Apr 2026 03:47:23 +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/2012/03/php-string-concat/</link>
		<comments>https://www.phppan.com/2012/03/php-string-concat/#comments</comments>
		<pubDate>Mon, 26 Mar 2012 01:12:12 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHP内核]]></category>
		<category><![CDATA[PHP源码]]></category>
		<category><![CDATA[PHP源码阅读笔记]]></category>
		<category><![CDATA[字符串]]></category>
		<category><![CDATA[深入理解PHP内核]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=1630</guid>
		<description><![CDATA[上周和刘志强同学讨论字符串的连接操作： 一般情况下我们用点号做字符串的连接操作，但是如果在某个长字符串中放一个 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>上周和<a href="http://liuzhiqiangruc.iteye.com/">刘志强同学</a>讨论字符串的连接操作：<br />
一般情况下我们用点号做字符串的连接操作，但是如果在某个长字符串中放一个变量，通常我们会采用在字符串中直接写入一个变量的方式来实现</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$var</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$str</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;test string begin &quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$var</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot; end&quot;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//或</span>
<span style="color: #000088;">$var</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$str</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;test string begin <span style="color: #006699; font-weight: bold;">$var</span> end&quot;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>这二者有什么区别呢？</p>
<p>以VLD扩展直接查看这两段代码生成的中间代码：<br />
点号连接：</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="shell" style="font-family:monospace;">number of ops:  7
compiled vars:  !0 = $var, !1 = $str
line     # *  op         ext  return  operands
------------------------------------------------
   2     0  &gt;   EXT_STMT
         1      ASSIGN                  !0, 10
   3     2      EXT_STMT
         3      CONCAT          ~1      'test+string+begin+', !0
         4      CONCAT          ~2      ~1, '+end'
         5      ASSIGN                  !1, ~2
         6    &gt; RETURN                  1</pre></td></tr></table></div>

<p>直接在字符串中插入变量：</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="shell" style="font-family:monospace;">number of ops:  8
compiled vars:  !0 = $var, !1 = $str
line     # *  op             ext  return  operands
----------------------------------------------------
   2     0  &gt;   EXT_STMT
         1      ASSIGN                      !0, 10
   3     2      EXT_STMT
         3      ADD_STRING          ~1      'test+string+begin+'
         4      ADD_VAR             ~1      ~1, !0
         5      ADD_STRING          ~1      ~1, '+end'
         6      ASSIGN                      !1, ~1
         7    &gt; RETURN                      1</pre></td></tr></table></div>

<p>对比这段生成的中间码，其原理完全不一样：</p>
<p>点号是典型的连接操作（当然，它本来就是连接操作），<br />
当使用多个点号是，每两个点号的结果都会使用一个临时变量存储起来，并作为下一个操作的一个操作数。如在我们的示例中，首先是执行第一个连接操作，将“test string begin ”和$var连接起来，得到“test string begin 10”，然后再执行第二个连接操作，将上一个操作得到的结果“test string begin 10”和&#8221; end&#8221;连接起来，并将结果存储在另一个临时变量，最后将第二个连接操作的结果赋值给$str。</p>
<p>连接操作对应的opcode为ZEND_CONCAT，对于所给的两个操作数，其最终通过concat_function函数将两个字符串连接起来，如果所给的变量的类型不是字符串，则会通过zend_make_printable_zval将其转换成字符串。concat_function函数会根据两个字符串的长度重新分配内存，并执行两次拷贝操作，将两个字符串拷贝到新的内存空间。<br />
这里针对两个字符串相同的情况有一个特殊处理。<br />
如下：</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="c" style="font-family:monospace;"><span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>result<span style="color: #339933;">==</span>op1<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>	<span style="color: #808080; font-style: italic;">/* special case, perform operations on result */</span>
	uint res_len <span style="color: #339933;">=</span> Z_STRLEN_P<span style="color: #009900;">&#40;</span>op1<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> Z_STRLEN_P<span style="color: #009900;">&#40;</span>op2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> erealloc<span style="color: #009900;">&#40;</span>Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> res_len<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000066;">memcpy</span><span style="color: #009900;">&#40;</span>Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>Z_STRLEN_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> Z_STRVAL_P<span style="color: #009900;">&#40;</span>op2<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> Z_STRLEN_P<span style="color: #009900;">&#40;</span>op2<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span>res_len<span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
	Z_STRLEN_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> res_len<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
	Z_STRLEN_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> Z_STRLEN_P<span style="color: #009900;">&#40;</span>op1<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> Z_STRLEN_P<span style="color: #009900;">&#40;</span>op2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span> emalloc<span style="color: #009900;">&#40;</span>Z_STRLEN_P<span style="color: #009900;">&#40;</span>result<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;">;</span>
	<span style="color: #000066;">memcpy</span><span style="color: #009900;">&#40;</span>Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> Z_STRVAL_P<span style="color: #009900;">&#40;</span>op1<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> Z_STRLEN_P<span style="color: #009900;">&#40;</span>op1<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000066;">memcpy</span><span style="color: #009900;">&#40;</span>Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>Z_STRLEN_P<span style="color: #009900;">&#40;</span>op1<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> Z_STRVAL_P<span style="color: #009900;">&#40;</span>op2<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> Z_STRLEN_P<span style="color: #009900;">&#40;</span>op2<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span>Z_STRLEN_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
	Z_TYPE_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> IS_STRING<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>示例执行了两次连接操作，则执行了两次内存分配操作和四次拷贝操作。</p>
<p>而直接在字符串中插入变量，其所有的操作都是添加操作，将字符串添加到返回值，将变量添加到返回值，<br />
所有的结果返回都是在一个临时变量中，如我们的示例，首先会将&#8221;test string begin &#8220;添加到临时变量，然后将临时变量和$var变量添加到临时变量，之后将临时变量和&#8221; end&#8221;添加到临时变量，最后将此此时变量赋值给$str。这里添加将字符串添加到临时变量，其对应的opcode为ZEND_ADD_STRING，将变量添加到临时变量，其对应的opcode为ZEND_ADD_VAR，虽然这两个操作的opcode不同，但其最终调用都是add_string_to_string，他们所不同的调用此函数的第三个参数，一个是操作码存储的ZVAL变量，一个是通过变更列表获取的ZVAL变量。<br />
其调用结构如下：</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// 添加字符串</span>
zval <span style="color: #339933;">*</span>str <span style="color: #339933;">=</span> <span style="color: #339933;">&amp;</span>EX_T<span style="color: #009900;">&#40;</span>opline<span style="color: #339933;">-&gt;</span>result.<span style="color: #202020;">u</span>.<span style="color: #202020;">var</span><span style="color: #009900;">&#41;</span>.<span style="color: #202020;">tmp_var</span><span style="color: #339933;">;</span>
add_string_to_string<span style="color: #009900;">&#40;</span>str<span style="color: #339933;">,</span> str<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>opline<span style="color: #339933;">-&gt;</span>op2.<span style="color: #202020;">u</span>.<span style="color: #202020;">constant</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//添加变量</span>
zval <span style="color: #339933;">*</span>str <span style="color: #339933;">=</span> <span style="color: #339933;">&amp;</span>EX_T<span style="color: #009900;">&#40;</span>opline<span style="color: #339933;">-&gt;</span>result.<span style="color: #202020;">u</span>.<span style="color: #202020;">var</span><span style="color: #009900;">&#41;</span>.<span style="color: #202020;">tmp_var</span><span style="color: #339933;">;</span>
zval <span style="color: #339933;">*</span>var <span style="color: #339933;">=</span> _get_zval_ptr_tmp<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>opline<span style="color: #339933;">-&gt;</span>op2<span style="color: #339933;">,</span> EX<span style="color: #009900;">&#40;</span>Ts<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>free_op2 TSRMLS_CC<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
add_string_to_string<span style="color: #009900;">&#40;</span>str<span style="color: #339933;">,</span> str<span style="color: #339933;">,</span> var<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>在添加变量时，如果添加的变量不是字符串，会通过zend_make_printable_zval将变量转换成字符串输出，如数组会转换成Array。<br />
add_string_to_string的实现在Zend/zend_operators.c文件中：</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="c" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">/* must support result==op1 */</span>
ZEND_API <span style="color: #993333;">int</span> add_string_to_string<span style="color: #009900;">&#40;</span>zval <span style="color: #339933;">*</span>result<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> zval <span style="color: #339933;">*</span>op1<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> zval <span style="color: #339933;">*</span>op2<span style="color: #009900;">&#41;</span> <span style="color: #808080; font-style: italic;">/* {{{ */</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #993333;">int</span> length <span style="color: #339933;">=</span> Z_STRLEN_P<span style="color: #009900;">&#40;</span>op1<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> Z_STRLEN_P<span style="color: #009900;">&#40;</span>op2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span> erealloc<span style="color: #009900;">&#40;</span>Z_STRVAL_P<span style="color: #009900;">&#40;</span>op1<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> length<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000066;">memcpy</span><span style="color: #009900;">&#40;</span>Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>Z_STRLEN_P<span style="color: #009900;">&#40;</span>op1<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> Z_STRVAL_P<span style="color: #009900;">&#40;</span>op2<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> Z_STRLEN_P<span style="color: #009900;">&#40;</span>op2<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	Z_STRVAL_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span>length<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
	Z_STRLEN_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> length<span style="color: #339933;">;</span>
	Z_TYPE_P<span style="color: #009900;">&#40;</span>result<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> IS_STRING<span style="color: #339933;">;</span>
	<span style="color: #b1b100;">return</span> SUCCESS<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #808080; font-style: italic;">/* }}} */</span></pre></td></tr></table></div>

<p>add_string_to_string函数的实现过程是针对即将生成的字符串的大小重新通过PHP内核的内存管理扩展内存空间（如果当前空间后续的内存够用，则天下太平，如果空间不够，则重新分配空间并执行拷贝操作），并将新的字符串复制到原始字串后面内存空间的过程。<br />
我们的示例执行了三次添加操作，也就执行了三次内存扩展操作和三次拷贝操作。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2012/03/php-string-concat/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP 源码阅读笔记二十三 ：urlencode函数</title>
		<link>https://www.phppan.com/2010/04/php-source-23-urlencode/</link>
		<comments>https://www.phppan.com/2010/04/php-source-23-urlencode/#comments</comments>
		<pubDate>Sat, 17 Apr 2010 05:29:01 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHP源码]]></category>
		<category><![CDATA[字符串]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=636</guid>
		<description><![CDATA[PHP 源码阅读笔记二十三 ：urlencode函数 有一段时间没有看PHP的源码了，最近一直在看以前买的书， [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>PHP 源码阅读笔记二十三 ：urlencode函数<br />
有一段时间没有看PHP的源码了，最近一直在看以前买的书，有一些书已经看过一遍了，但是事隔一年又有不同的感受<br />
<br />
urlencode函数在开发的过程中经常有遇到，它作用于字符串编码并将其用于 URL 的请求部分<br />
urlencode函数的作用是编码 URL 字符串<br />
<strong>string urlencode ( string str )</strong><br />
      返回字符串，此字符串中除了 -_. 之外的所有非字母数字字符都将被替换成百分号（%）后跟两位十六进制数，空格则编码为加号（+）。此编码与 WWW 表单 POST 数据的编码方式是一样的，同时与 application/x-www-form-urlencoded 的媒体类型编码方式一样。由于历史原因，此编码在将空格编码为加号（+）方面与 RFC1738 编码（参见 rawurlencode()）不同。<br />
在standard/url.c文件的493行，可以看到此函数的实现</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="c" style="font-family:monospace;">out_str <span style="color: #339933;">=</span> php_url_encode<span style="color: #009900;">&#40;</span>in_str<span style="color: #339933;">,</span> in_str_len<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>out_str_len<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
RETURN_STRINGL<span style="color: #009900;">&#40;</span>out_str<span style="color: #339933;">,</span> out_str_len<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>在查看php_url_encode函数时，我纠结了好一段时间，因为它有一个#ifndef CHARSET_EBCDIC的编译判断，我一直将#ifndef看成了#ifdef，导致理解起来怪怪的<br />
php_url_encode函数是一个遍历整个字符串，并针对每个字符进行替换的过程，<br />
对于除了 -_. 之外的所有非字母数字字符都将被替换成百分号（%）后跟两位十六进制数，<br />
此处在编译时有针对EBCDIC编码的处理</p>
<p>空格则编码为加号（+）(<br />
if (c == &#8216; &#8216;) {<br />
*to++ = &#8216;+&#8217;;<br />
} </p>
<p>另外：将urlencode从代码中分离出来的独立程序请猛击：<a href = "http://www.wqsl.net/blogs/web/php/10/200804/03-60.html">www.wqsl.net/blogs/web/php/10/200804/03-60.html</a><br />
不过没有测试过此段代码</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2010/04/php-source-23-urlencode/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
