<?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>phpdo&#124;学习PHP的笔记</title>
	<atom:link href="http://www.phpdo.net/index.php/feed" rel="self" type="application/rss+xml" />
	<link>http://www.phpdo.net</link>
	<description>心有多大，世界有多大</description>
	<lastBuildDate>Mon, 06 Feb 2012 12:33:33 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>SlightPHP</title>
		<link>http://www.phpdo.net/index.php/slightphp.html</link>
		<comments>http://www.phpdo.net/index.php/slightphp.html#comments</comments>
		<pubDate>Mon, 06 Feb 2012 12:33:33 +0000</pubDate>
		<dc:creator>老张</dc:creator>
				<category><![CDATA[php实例]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[SlightPHP]]></category>

		<guid isPermaLink="false">http://www.phpdo.net/?p=1850</guid>
		<description><![CDATA[SlightPHP是一款轻量级的php框架。]]></description>
			<content:encoded><![CDATA[<p>SlightPHP是一款轻量级的<strong><a title="php" href="http://www.phpdo.net" target="_blank">php</a></strong>框架。<br />
<strong><a title="slightphp" href="http://www.phpdo.net/index.php/slightphp.html" target="_blank">SlightPHP</a></strong>的主要特点：<br />
1 独有的”框架”与”plugins”分离方式，与现在主流框架完全不同，把核心框架与其它功能独立分开，灵活性大，耦合度小，很方便移植<br />
2 框架本身核心代码非常小，速度快效率极高，更支持php模块方式加载（请编译pecl目录下的源码，或者直接编译到php里）<br />
3 框架支持nginx,lighttpd,apache,iis等web服务器<br />
4 插件SDb 支持mysql,mysqli,pdo,mssql,oracle等主流数据库，同时更支持数据库读写库分离，特适合大流量网站<br />
5 插件SRoute 支持各种简洁路由支持，精简URL<br />
6 插件STpl模板类，高效与灵活，比Smarty轻量级不少！<br />
7 插件SCache(memcache)采用consistent hashing算法，支持分布式服务与依赖KEY，同时也支持file,apc缓存<br />
8 其它更多灵活可定制的插件，请查看wiki或者samples下的例子</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpdo.net/index.php/slightphp.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>mysql_real_escape_string</title>
		<link>http://www.phpdo.net/index.php/mysql_real_escape_string.html</link>
		<comments>http://www.phpdo.net/index.php/mysql_real_escape_string.html#comments</comments>
		<pubDate>Thu, 22 Dec 2011 12:22:45 +0000</pubDate>
		<dc:creator>老张</dc:creator>
				<category><![CDATA[php-基础语法]]></category>
		<category><![CDATA[mysql_real_escape_string]]></category>

		<guid isPermaLink="false">http://www.phpdo.net/?p=1841</guid>
		<description><![CDATA[php 的mysql_real_escape_string()  函数可以转义 SQL 语句中使用的字符串中的特殊字符。 下列字符受影响： \x00 \n \r \ ' " \x1a 如果成功，则mysql_real_escape_string函数返回被转义的字符串。如果失败，则返回 false。 语法 mysql_real_escape_string(string,connection) &#160; 参数 描述 string 必需。规定要转义的字符串。 connection 可选。规定 MySQL 连接。如果未规定，则使用上一个连接。 说明 mysql_real_escape_string函数将 string 中的特殊字符转义，并考虑到连接的当前字符集，因此可以安全用于 mysql_query()。 提示和注释 提示：可使用mysql_real_escape_string函数来预防数据库攻击。 例子 1 &#60;?php $con = mysql_connect(“localhost”, “hello”, “321&#8243;); if (!$con) { die(&#8216;Could not connect: &#8216; . mysql_error()); } // 获得用户名和密码的代码 // 转义用户名和密码，以便在 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.phpdo.net" target="_blank">php</a> 的<a href="http://www.phpdo.net/index.php/mysql_real_escape_string.html" target="_blank">mysql_real_escape_string</a>()  函数可以转义 SQL 语句中使用的字符串中的特殊字符。</p>
<p>下列字符受影响：<br />
<code><br />
\x00<br />
\n<br />
\r<br />
\<br />
'<br />
"<br />
\x1a<br />
</code><br />
如果成功，则<a href="http://www.phpdo.net/index.php/mysql_real_escape_string.html" target="_blank">mysql_real_escape_string</a>函数返回被转义的字符串。如果失败，则返回 false。</p>
<p>语法</p>
<p>mysql_real_escape_string(string,connection)</p>
<p>&nbsp;</p>
<table width="396" border="1" cellspacing="0" cellpadding="2">
<tbody>
<tr>
<td valign="top" width="112">参数</td>
<td valign="top" width="282">描述</td>
</tr>
<tr>
<td valign="top" width="116">string</td>
<td valign="top" width="279">必需。规定要转义的字符串。</td>
</tr>
<tr>
<td valign="top" width="119">connection</td>
<td valign="top" width="277">可选。规定 MySQL 连接。如果未规定，则使用上一个连接。</td>
</tr>
</tbody>
</table>
<p>说明</p>
<p><a href="http://www.phpdo.net/index.php/mysql_real_escape_string.html" target="_blank">mysql_real_escape_string</a>函数将 string 中的特殊字符转义，并考虑到连接的当前字符集，因此可以安全用于 <a href="http://www.phpdo.net/index.php/mysql_query.html" target="_blank">mysql_query</a>()。</p>
<p>提示和注释</p>
<p>提示：可使用<a href="http://www.phpdo.net/index.php/mysql_real_escape_string.html" target="_blank">mysql_real_escape_string</a>函数来预防数据库攻击。</p>
<p>例子 1</p>
<p>&lt;?php<br />
$con = mysql_connect(“localhost”, “hello”, “321&#8243;);<br />
if (!$con)<br />
{<br />
die(&#8216;Could not connect: &#8216; . mysql_error());<br />
}</p>
<p>// 获得用户名和密码的代码</p>
<p>// 转义用户名和密码，以便在 SQL 中使用<br />
$user = mysql_real_escape_string($user);<br />
$pwd = mysql_real_escape_string($pwd);</p>
<p>$sql = “SELECT * FROM users WHERE<br />
user=&#8217;” . $user . “&#8216; AND password=&#8217;” . $pwd . “&#8216;”</p>
<p>// 更多代码</p>
<p>mysql_close($con);<br />
?&gt;</p>
<p>例子 2</p>
<p><a href="http://www.phpdo.net/index.php/category/database-2" target="_blank">数据库</a>攻击。本例演示如果我们不对用户名和密码应用 <a href="http://www.hhtp://www.phpdo.net" target="_blank">mysql_real_escape_string</a>() 函数会发生什么：</p>
<p>&lt;?php<br />
$con = mysql_connect(“localhost”, “hello”, “321&#8243;);<br />
if (!$con)<br />
{<br />
die(&#8216;Could not connect: &#8216; . mysql_error());<br />
}</p>
<p>$sql = “SELECT * FROM users<br />
WHERE user=&#8217;{$_POST['user']}&#8217;<br />
AND password=&#8217;{$_POST['pwd']}&#8217;”;<br />
mysql_query($sql);</p>
<p>// 不检查用户名和密码<br />
// 可以是用户输入的任何内容，比如：<br />
$_POST['user'] = &#8216;john&#8217;;<br />
$_POST['pwd'] = “&#8216; OR ”=&#8217;”;</p>
<p>// 一些代码&#8230;</p>
<p>mysql_close($con);<br />
?&gt;<br />
那么 SQL 查询会成为这样：<br />
SELECT * FROM users<br />
WHERE user=&#8217;john&#8217; AND password=” OR ”=”<br />
这意味着任何用户无需输入合法的密码即可登陆。<br />
例子 3<br />
预防数据库攻击的正确做法：<br />
&lt;?php<br />
function check_input($value)<br />
{<br />
// 去除斜杠<br />
if (get_magic_quotes_gpc())<br />
{<br />
$value = stripslashes($value);<br />
}<br />
// 如果不是数字则加引号<br />
if (!is_numeric($value))<br />
{<br />
$value = “&#8216;” . mysql_real_escape_string($value) . “&#8216;”;<br />
}<br />
return $value;<br />
}</p>
<p>$con = mysql_connect(“localhost”, “hello”, “321&#8243;);<br />
if (!$con)<br />
{<br />
die(&#8216;Could not connect: &#8216; . mysql_error());<br />
}</p>
<p>// 进行安全的 SQL<br />
$user = check_input($_POST['user']);<br />
$pwd = check_input($_POST['pwd']);<br />
$sql = “SELECT * FROM users WHERE<br />
user=$user AND password=$pwd”;</p>
<p>mysql_query($sql);</p>
<p>mysql_close($con);<br />
?&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpdo.net/index.php/mysql_real_escape_string.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>$_SERVER</title>
		<link>http://www.phpdo.net/index.php/server.html</link>
		<comments>http://www.phpdo.net/index.php/server.html#comments</comments>
		<pubDate>Thu, 15 Dec 2011 13:31:34 +0000</pubDate>
		<dc:creator>老张</dc:creator>
				<category><![CDATA[php-基础语法]]></category>
		<category><![CDATA[$_SERVER]]></category>

		<guid isPermaLink="false">http://www.phpdo.net/?p=1836</guid>
		<description><![CDATA[服务器变量 $_SERVER 详解：]]></description>
			<content:encoded><![CDATA[<p>服务器变量 $_SERVER 详解：</p>
<p>1、$_SESSION['PHP_SELF'] &#8212; 获取当前正在执行脚本的文件名</p>
<p>2、$_SERVER['SERVER_PROTOCOL'] &#8212; 请求页面时通信协议的名称和版本。例如，“HTTP/1.0”。</p>
<p>3、$_SERVER['REQUEST_TIME'] &#8212; 请求开始时的时间戳。从 PHP 5.1.0 起有效。和time函数效果一样。</p>
<p>4、$_SERVER['argv'] &#8212; 传递给该脚本的参数。我试了下，get方法可以得到$_SERVER['argv'][0]；post方法无法给他赋值。</p>
<p>5、$_SERVER['SERVER_NAME'] &#8212; 返回当前主机名。</p>
<p>6、$_SERVER['SERVER_SOFTWARE'] &#8212; 服务器标识的字串，在响应请求时的头信息中给出。 如Microsoft-IIS/6.0</p>
<p>7、$_SERVER['REQUEST_METHOD'] &#8212; 访问页面时的请求方法。例如：“GET”、“HEAD”，“POST”，“PUT”。</p>
<p>8、$_SERVER['QUERY_STRING'] &#8212; 查询（query）的字符串（URL 中第一个问号 ? 之后的内容）。</p>
<p>9、$_SERVER['DOCUMENT_ROOT'] &#8212; 当前运行脚本所在的文档根目录。在服务器配置文件中定义。 如E:\server</p>
<p>10、$_SERVER['HTTP_ACCEPT'] &#8212; 当前请求的 Accept: 头信息的内容。</p>
<p>11、$_SERVER['HTTP_ACCEPT_CHARSET'] &#8212; 当前请求的 Accept-Charset: 头信息的内容。例如：“iso-8859-1,*,utf-8”。</p>
<p>12、$_SERVER['HTTP_ACCEPT_ENCODING'] &#8212; 当前请求的 Accept-Encoding: 头信息的内容。例如：“gzip”。</p>
<p>13、$_SERVER['HTTP_ACCEPT_LANGUAGE'] &#8212; 当前请求的 Accept-Language: 头信息的内容。例如：“en”。</p>
<p>14、$_SERVER['HTTP_CONNECTION'] &#8212; 当前请求的 Connection: 头信息的内容。例如：“Keep-Alive”。</p>
<p>15、$_SERVER['HTTP_HOST'] &#8212; 当前请求的 Host: 头信息的内容。</p>
<p>16、$_SERVER['HTTP_REFERER'] &#8212; 链接到当前页面的前一页面的 URL 地址。</p>
<p>17、$_SERVER['HTTP_USER_AGENT'] &#8212; 返回用户使用的浏览器信息。也可以使用 get_browser() 得到此信息。</p>
<p>18、$_SERVER['HTTPS'] &#8212; 如果通过https访问，则被设为一个非空的值，否则返回off.</p>
<p>19、$_SERVER['REMOTE_ADDR'] &#8212; 正在浏览当前页面用户的 IP 地址。</p>
<p>20、$_SERVER['REMOTE_HOST'] &#8212; 正在浏览当前页面用户的主机名。反向域名解析基于该用户的 REMOTE_ADDR。如本地测试返回127.0.0.1</p>
<p>21、$_SERVER['REMOTE_PORT'] &#8212; 用户连接到服务器时所使用的端口。我在本机测试没通过，不知道什么原因。</p>
<p>22、$_SERVER['SCRIPT_FILENAME'] &#8212; 当前执行脚本的绝对路径名。如返回E:\server\index.php</p>
<p>23、$_SERVER['SERVER_ADMIN'] &#8212; 该值指明了 Apache 服务器配置文件中的 SERVER_ADMIN 参数。如果脚本运行在一个虚拟主机上，则该值是那个虚拟主机的值</p>
<p>24、$_SERVER['SERVER_PORT'] &#8212; 服务器所使用的端口。默认为“80”。如果使用 SSL 安全连接，则这个值为用户设置的 HTTP 端口。</p>
<p>25、$_SERVER['SERVER_SIGNATURE'] &#8212; 包含服务器版本和虚拟主机名的字符串。</p>
<p>26、$_SERVER['PATH_TRANSLATED'] &#8212; 当前脚本所在文件系统（不是文档根目录）的基本路径。这是在服务器进行虚拟到真实路径的映像后的结果。 Apache 2 用 户可以使用 httpd.conf 中的 AcceptPathInfo On 来定义 PATH_INFO。</p>
<p>27、$_SERVER['SCRIPT_NAME'] &#8212; 包含当前脚本的路径。这在页面需要指向自己时非常有用。__FILE__ 包含当前文件的绝对路径和文件名（例如包含文件）。</p>
<p>28、$_SERVER['REQUEST_URI'] &#8212; 访问此页面所需的 URI。例如，“/index.html”。</p>
<p>29、$_SERVER['PHP_AUTH_DIGEST'] &#8212; 当作为 Apache 模块运行时，进行 HTTP Digest 认证的过程中，此变量被设置成客户端发送的“Authorization”HTTP 头内容（以便作进一步的认证操作）。</p>
<p>30、$_SERVER['PHP_AUTH_USER']&#8211; 当 PHP 运行在 Apache 或 IIS（PHP 5 是 ISAPI）模块方式下，并且正在使用 HTTP 认证功能，这个变量便是用户输入的用户名。</p>
<p>31、$_SERVER['PHP_AUTH_PW'] &#8212; 当 PHP 运行在 Apache 或 IIS（PHP 5 是 ISAPI）模块方式下，并且正在使用 HTTP 认证功能，这个变量便是用户输入的密码。</p>
<p>32、$_SERVER['AUTH_TYPE']&#8211;当 PHP 运行在 Apache 模块方式下，并且正在使用 HTTP 认证功能，这个变量便是认证的类型。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpdo.net/index.php/server.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP函数的实现原理及性能分析</title>
		<link>http://www.phpdo.net/index.php/php-function.html</link>
		<comments>http://www.phpdo.net/index.php/php-function.html#comments</comments>
		<pubDate>Tue, 13 Dec 2011 01:25:23 +0000</pubDate>
		<dc:creator>老张</dc:creator>
				<category><![CDATA[老张的碎嘴]]></category>
		<category><![CDATA[PHP函数的实现原理及性能分析]]></category>

		<guid isPermaLink="false">http://www.phpdo.net/?p=1452</guid>
		<description><![CDATA[在任何语言中，函数都是最基本的组成单元。对于PHP的函数，它具有哪些特点？函数调用是怎么实现的？PHP函数的性能如何，有什么使用建议？本文将从原理出发进行分析结合实际的性能测试尝试对这些问题进行回答，在了解实现的同时更好的编写php程序。同时也会对一些常见的php函数进行介绍。]]></description>
			<content:encoded><![CDATA[<p>在任何语言中，函数都是最基本的组成单元。对于<a href="http://www.phpdo.net/" target="_blank">PHP</a>的函数，它具有哪些特点？函数调用是怎么实现的？<a href="http://www.phpdo.net/" target="_blank">PHP</a>函数的性能如何，有什么使用建议？本文将从原理出发进行分析结合实际的性能测试尝试对这些问题进行回答，在了解实现的同时更好的编写php程序。同时也会对一些常见的php函数进行介绍。</p>
<p>php函数的分类</p>
<p>在<a href="http://www.phpdo.net/" target="_blank">PHP</a>中，横向划分的话，函数分为两大类： user function(内置函数) 和internal function（内置函数）。</p>
<p>前者就是用户在程序中自定义的一些函数和方法，后者则是php本身提供的各类库函数（比如sprintf、array_push等）。用户也可以通过扩展的方法来编写库函数，这个将在后面介绍。对于user function，又可以细分为function（函数）和method（类方法），本文中将就这三种函数分别进行分析和测试。</p>
<p>php函数的实现</p>
<p>一个php函数最终是如何执行，这个流程是怎么样的呢？</p>
<p>要回答这个问题，我们先来看看php代码的执行所经过的流程。</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/04/1.jpg"><img class="aligncenter size-full wp-image-1825" title="1" src="http://www.phpdo.net/wp-content/uploads/2011/04/1.jpg" alt="" width="232" height="551" /></a></p>
<p>&nbsp;</p>
<p><a href="http://www.phpdo.net/" target="_blank">php</a> 函数的实现</p>
<p>从图1可以看到，php 实现了一个典型的动态语言执行过程：拿到一段代码后，经过词法解析、语法解析等阶段后，源程序会被翻译成一个个指令(opcodes)，然后ZEND虚拟机顺次执行这些指令完成操作。Php本身是用c实现的，因此最终调用的也都是c的函数，实际上，我们可以把php看做是一个c开发的软件。</p>
<p>通过上面描述不难看出，php中函数的执行也是被翻译成了opcodes来调用，每次函数调用实际上是执行了一条或多条指令。</p>
<p>对于每一个函数，zend都通过以下的数据结构来描述<br />
<code>typedef union _zend_function {<br />
zend_uchar type;    /* MUST be the first element of this struct! */<br />
struct {<br />
zend_uchar type;  /* never used */<br />
char *function_name;<br />
zend_class_entry *scope;<br />
zend_uint fn_flags;<br />
union _zend_function *prototype;<br />
zend_uint num_args;<br />
zend_uint required_num_args;<br />
zend_arg_info *arg_info;<br />
zend_bool pass_rest_by_reference;<br />
unsigned char return_reference;<br />
} common;   zend_op_array op_array;<br />
zend_internal_function internal_function;<br />
} zend_function;   typedef struct _zend_function_state {<br />
HashTable *function_symbol_table;<br />
zend_function *function;<br />
void *reserved[ZEND_MAX_RESERVED_RESOURCES];<br />
} zend_function_state;</code></p>
<p>其中type标明了函数的类型：用户函数、内置函数、重载函数。Common中包含函数的基本信息，包括函数名，参数信息，函数标志（普通函数、静态方法、抽象方法）等内容。另外，对于用户函数，还有一个函数符号表，记录了内部变量等，这个将在后面详述。</p>
<p>Zend维护了一个全局function_table，这是一个大的hahs表。函数调用的时候会首先根据函数名从表中找到对应的zend_function。当进行函数调用时候，虚拟机会根据type的不同决定调用方法， 不同类型的函数，其执行原理是不相同的 。</p>
<p>内置函数</p>
<p>内置函数，其本质上就是真正的c函数，每一个内置函数，php在最终编译后都会展开成为一个名叫zif_xxxx的function，比如我们常见的sprintf，对应到底层就是zif_sprintf。Zend在执行的时候，如果发现是内置函数，则只是简单的做一个转发操作。</p>
<p>Zend提供了一系列的api供调用，包括参数获取、数组操作、内存分配等。内置函数的参数获取，通过zend_parse_parameters方法来实现，对于数组、字符串等参数，zend实现的是浅拷贝，因此这个效率是很高的。可以这样说，对于php内置函数，其效率和相应c函数几乎相同，唯一多了一次转发调用。</p>
<p>内置函数在php中都是通过so的方式进行动态加载，用户也可以根据需要自己编写相应的so，也就是我们常说的扩展。ZEND提供了一系列的api供扩展使用</p>
<p>用户函数</p>
<p>和内置函数相比，用户通过php实现的自定义函数具有完全不同的执行过程和实现原理。如前文所述，我们知道php代码是被翻译成为了一条条opcode来执行的，用户函数也不例外，实际中每个函数对应到一组opcode，这组指令被保存在zend_function中。于是，用户函数的调用最终就是对应到一组opcodes的执行。</p>
<p>局部变量的保存及递归的实现</p>
<p>我们知道，函数递归是通过堆栈来完成的。在php中，也是利用类似的方法来实现。Zend为每个php函数分配了一个活动符号表(active_sym_table)，记录当前函数中所有局部变量的状态。所有的符号表通过堆栈的形式来维护，每当有函数调用的时候，分配一个新的符号表并入栈。当调用结束后当前符号表出栈。由此实现了状态的保存和递归。<br />
对于栈的维护，zend在这里做了优化。预先分配一个长度为N的静态数组来模拟堆栈，这种通过静态数组来模拟动态数据结构的手法在我们自己的程序中也经常有使用，这种方式避免了每次调用带来的内存分配、销毁。ZEND只是在函数调用结束时将当前栈顶的符号表数据clean掉即可。</p>
<p>因为静态数组长度为N，一旦函数调用层次超过N，程序不会出现栈溢出，这种情况下zend就会进行符号表的分配、销毁，因此会导致性能下降很多。在zend里面，N目前取值是32。因此，我们编写php程序的时候，函数调用层次最好不要超过32。当然，如果是web应用，本身可以函数调用层次的深度。</p>
<p>参数的传递</p>
<p>和内置函数调用zend_parse_params来获取参数不同，用户函数中参数的获取是通过指令来完成的。函数有几个参数就对应几条指令。具体到实现上就是普通的变量赋值。<br />
通过上面的分析可以看出，和内置函数相比，由于是自己维护堆栈表，而且每条指令的执行也是一个c函数，用户函数的性能相对会差很多，后面会有具体的对比分析。因此，如果一个功能有对应php内置函数实现的尽量不要自己重新写函数去实现。</p>
<p>类方法</p>
<p>类方法其执行原理和用户函数是相同的，也是翻译成opcodes顺次调用。类的实现，zend用一个数据结构zend_class_entry来实现，里面保存了类相关的一些基本信息。这个entry是在php编译的时候就已经处理完成。</p>
<p>在zend_function的common中，有一个成员叫做scope，其指向的就是当前方法对应类的zend_class_entry。关于php中面向对象的实现，这里就不在做更详细的介绍，今后将专门写一篇文章来详述php中面向对象的实现原理。就函数这一块来说，method实现原理和function完全相同，理论上其性能也差不多，后面我们将做详细的性能对比。</p>
<p>性能对比</p>
<p>函数名长度对性能的影响</p>
<p>测试方法</p>
<ul>
<li>测试方法对名字长度为1、2、4、8、16的函数进行比较，测试比较它们每秒可执行次数，确定函数名长度对性能的影响</li>
</ul>
<ul>
<li>测试结果如下图函数名长度对性能的影响</li>
</ul>
<ul>
<li>结果分析从图上可以看出，函数名的长度对性能还是会有一定的影响。一个长度为1的函数和长度为16的 <strong>空函数调用</strong> ，其性能差了1倍。分析一下源码不难找到原因，如前面叙述所说，函数调用的时候zend会先在一个全局的funtion_table中通过函数名查询相关信息，function_table是一个哈希表。必然的，名字越长查询所需要的时间就越多。 <strong>因此，在实际编写程序的时候，对多次调用的函数，名字建议不要太长</strong></li>
</ul>
<div><a href="http://www.phpdo.net/wp-content/uploads/2011/04/21.jpg"><img class="aligncenter size-full wp-image-1828" title="2" src="http://www.phpdo.net/wp-content/uploads/2011/04/21.jpg" alt="" width="558" height="289" /></a></div>
<div><strong><br />
</strong></div>
<p>虽然函数名长度对性能有一定影响，但具体有多大呢？这个问题应该还是需要结合实际情况来考虑，如果一个函数本身比较复杂的话，那么对整体的性能影响并不大。</p>
<p>一个建议是对于那些会调用很多次，本身功能又比较简单的函数，可以适当取一些言简意赅的名字。</p>
<h5><a name="函数个数对性能的影响"></a>函数个数对性能的影响</h5>
<ul>
<li>测试方法在以下三种环境下进行函数调用测试，分析结果：1.程序仅包含1个函数 2.程序包含100个函数 3.程序包含1000个函数。测试这三种情况下每秒所能调用的函数次数</li>
</ul>
<ul>
<li>测试结果如下图函数名长度对性能的影响</li>
</ul>
<ul>
<li>结果分析从测试结果可以看出，这三种情况下性能几乎相同，函数个数增加时性能下降微乎其微，可以忽略。从实现原理分析，几种实现下唯一的区别在于函数获取的部分。如前文所述，所有的函数都放在一个hash表中，在不同个数下查找效率都应该还是接近于O(1)，所以性能差距不大。</li>
</ul>
<div><a href="http://www.phpdo.net/wp-content/uploads/2011/04/3.jpg"><img class="aligncenter size-full wp-image-1827" title="3" src="http://www.phpdo.net/wp-content/uploads/2011/04/3.jpg" alt="" width="489" height="293" /></a></div>
<div></div>
<div>不同类型函数调用消耗</div>
<ul>
<li>测试方法选取用户函数、类方法、静态方法、内置函数各一种，函数本身不做任何事情，直接返回，主要测试空函数调用的消耗。测试结果为每秒可执行次数测试中为去除其他影响，所有函数名字长度相同</li>
</ul>
<ul>
<li>测试结果如下图不同类型函数调用消耗</li>
</ul>
<ul>
<li>结果分析通过测试结果可以看到，对于用户自己编写的php函数，不管是哪种类型，其效率是差不多的，均在280w/s左右。如我们预期，即使是空调，内置函数其效率也要高很多，达到780w/s，是前者是3倍。可见，内置函数调用的开销还是远低于用户函数。从前面原理分析可知主要差距在于用户函数调用时初始化符号表、接收参数等操作。</li>
</ul>
<div></div>
<div><a href="http://www.phpdo.net/wp-content/uploads/2011/04/4.jpg"><img class="aligncenter size-full wp-image-1829" title="4" src="http://www.phpdo.net/wp-content/uploads/2011/04/4.jpg" alt="" width="559" height="316" /></a></div>
<div></div>
<div>内置函数和用户函数性能对比</div>
<ul>
<li>测试方法内置函数和用户函数的性能对比，这里我们选取几个常用的函数，然后用php实现相同功能的函数进行一下性能对比。测试中，我们选取字符串、数学、数组中各一个典型进行对比，这几个函数分别是字符串截取(substr)、10进制转2进制(decbin)、求最小值(min)和返回数组中的所以key(array_keys)。</li>
</ul>
<ul>
<li>测试结果如下图内置函数和用户函数性能对比</li>
</ul>
<ul>
<li>结果分析从测试结果可以看出，如我们预期，内置函数在总体性能上远高于普通用户函数。尤其对于涉及到字符串类操作的函数，差距达到了1个数量级。因此，函数使用的一个原则就是如果某功能有相应的内置函数，尽量使用它而不是自己编写php函数。对于一些涉及到大量字符串操作的功能，为提高性能，可以考虑用扩展来实现。比如常见的富文本过滤等。</li>
</ul>
<div><a href="http://www.phpdo.net/wp-content/uploads/2011/04/5.jpg"><img class="aligncenter size-full wp-image-1830" title="5" src="http://www.phpdo.net/wp-content/uploads/2011/04/5.jpg" alt="" width="556" height="328" /></a></div>
<div></div>
<div>和C函数性能对比</div>
<ul>
<li>测试方法我们选取字符串操作和算术运算各3种函数进行比对，php用扩展实现。三种函数是简单的一次算法运算、字符串比较和多次的算法运算。除了本身的两类函数外，还会测试将函数空调开销去掉后的性能，一方面比对一下两种函数（c和php内置）本身的性能差异，另外就是侧面印证空调函数的消耗测试点为执行10w次操作的时间消耗</li>
</ul>
<ul>
<li>测试结果如下图和C函数性能对比</li>
</ul>
<ul>
<li>结果分析内置函数和C函数的开销在去掉php函数空调用的影响后差距较小，随着函数功能越来越复杂，双方性能趋近于相同。这个从之前的函数实现分析中也容易得到论证，毕竟内置函数就是C实现的。函数功能越复杂，c和php的性能差距越小相对c来说，php函数调用的开销大很多，对于简单函数来说性能还是有一定影响。因此php中函数不宜嵌套封装太深。</li>
</ul>
<div></div>
<div><a href="http://www.phpdo.net/wp-content/uploads/2011/04/6.jpg"><img class="aligncenter size-full wp-image-1831" title="6" src="http://www.phpdo.net/wp-content/uploads/2011/04/6.jpg" alt="" width="560" height="281" /></a></div>
<div></div>
<div>伪函数及其性能</div>
<p>在php中，有这样一些函数，它们在使用上是标准的函数用法，但底层实现却和真正函数调用完全不同，这些函数不属于前文提到的三种function中的任何一类，其实质是一条单独的opcode，这里估且叫做伪函数或者指令函数。</p>
<p>如上所说，伪函数使用起来和标准的函数并无二致，看起来具有相同的特征。但是他们最终执行的时候是被zend反映成了一条对应的指令（opcode）来调用，因此其实现更接近于if、for、算术运算等操作。</p>
<ul>
<li>php中的伪函数issetemptyunseteval</li>
</ul>
<p>通过上面的介绍可以看出，伪函数由于被直接翻译成指令来执行，和普通函数相比少了一次函数调用所带来的开销，因此性能会更好一些。我们通过如下测试来做一个对比。 Array_key_exists和isset两者都可以判断数组中某个key是否存在，看一下他们的性能</p>
<p>&nbsp;</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/04/7.jpg"><img class="aligncenter size-full wp-image-1832" title="7" src="http://www.phpdo.net/wp-content/uploads/2011/04/7.jpg" alt="" width="538" height="268" /></a></p>
<p>伪函数及其性能</p>
<p>从图上可以看出，和array_key_exists相比，isset性能要高出很多，基本是前者的4倍左右，而即使是和空函数调用相比，其性能也要高出1倍左右。由此也侧面印证再次说明了php函数调用的开销还是比较大的。</p>
<p>常用<strong>php</strong>函数实现及介绍</p>
<p>count</p>
<p>count是我们经常用到的一个函数，其功能是返回一个数组的长度。</p>
<p>count这个函数，其复杂度是多少呢？</p>
<p>一种常见的说法是count函数会遍历整个数组然后求出元素个数，因此复杂度是O(n)。那实际情况是不是这样呢？</p>
<p>我们回到count的实现来看一下，通过源码可以发现，对于数组的count操作，函数最终的路径是zif_count-&gt; php_count_recursive-&gt; zend_hash_num_elements，而zend_hash_num_elements的行为是 return ht-&gt;nNumOfElements，可见，这是一个O(1)而不是O(n)的操作。实际上，数组在php底层就是一个hash_table，对于hash表，zend中专门有一个元素nNumOfElements记录了当前元素的个数，因此对于一般的count实际上直接就返回了这个值。由此，我们得出结论： <strong>count是O(1)的复杂度，和具体数组的大小无关。</strong></p>
<p>非数组类型的变量，count的行为时怎样？</p>
<p>对于未设置变量返回0，而像int、double、string等则会返回1</p>
<p>strlen</p>
<p>Strlen用于返回一个字符串的长度。那么，他的实现原理是如何的呢？</p>
<p>我们都知道在c中strlen是一个o(n)的函数，会顺序遍历字符串直到遇到\0，然后出长度。Php中是否也这样呢？答案是否定的，php里字符串是用一个复合结构来描述，包括指向具体数据的指针和字符串长度（和c++中string类似），因此strlen就直接返回字符串长度了，是常数级别的操作。</p>
<p>另外，对于非字符串类型的变量调用strlen，它会首先将变量强制转换为字符串再求长度，这点需要注意。</p>
<p>isset和array_key_exists</p>
<p>这两个函数最常见的用法都是判断一个key是否在数组中存在。但是前者还可以用于判断一个变量是否被设置过。</p>
<p>如前文所述，isset并非真正的函数，因此它的效率会比后者高很多。推荐用它代替array_key_exists。</p>
<p>array_push和array[]</p>
<p>两者都是往数组尾部追加一个元素。不同的是前者可以一次push多个。他们最大的区别在于一个是函数一个是语言结构，因此后者效率要更高。因此如果只是普通的追加元素，建议使用array []。</p>
<p>rand和mt_rand</p>
<p>两者都是提供产生随机数的功能，前者使用libc标准的rand。后者用了 Mersenne Twister 中已知的特性作为随机数发生器，它可以产生随机数值的平均速度比 libc 提供的 rand() 快四倍。因此如果对性能要求较高，可以考虑用mt_rand代替前者。</p>
<p>我们都知道，rand产生的是伪随机数，在C中需要用srand显示指定种子。但是在php中，rand会自己帮你默认调用一次srand，一般情况下不需要自己再显示的调用。</p>
<p>需要注意的是，如果特殊情况下需要调用srand时，一定要配套调用。就是说srand对于rand，mt_srand对应srand，切不可混合使用，否则是无效的。</p>
<p>sort和usort</p>
<p>两者都是用于排序，不同的是前者可以指定排序策略，类似我们C里面的qsort和C++的sort。</p>
<p>在排序上两者都是采用标准的快排来实现，对于有排序需求的，如非特殊情况调用php提供的这些方法就可以了，不用自己重新实现一遍，效率会低很多。原因见前文对于用户函数和内置函数的分析比对。\urlencode和rawurlencode</p>
<p>这两个都是用于url编码， 字符串中除了 -_. 之外的所有非字母数字字符都将被替换成百分号（%）后跟两位十六进制数。两者唯一的区别在于对于空格，urlencode会编码为+，而rawurlencode会编码为%20。</p>
<p>一般情况下除了搜索引擎，我们的策略都是空格编码为%20。因此采用后者的居多。</p>
<p>注意的是encode和decode系列一定要配套使用。</p>
<p>strcmp系列函数</p>
<p>这一系列的函数包括strcmp、strncmp、strcasecmp、strncasecmp，实现功能和C函数相同。但也有不同，由于php的字符串是允许\0出现，因此在判断的时候底层使用的是memcmp系列而非strcmp，理论上来说更快。</p>
<p>另外由于php直接能获取到字符串长度，因此会首先这方面的检查，很多情况下效率就会高很多</p>
<p>了。</p>
<p>is_int和is_numeric</p>
<p>这两个函数功能相似又不完全相同，使用的时候一定需要注意他们的区别。</p>
<p>Is_int：判断一个变量类型是否是整数型，php变量中专门有一个字段表征类型，因此直接判断这个类型即可，是一个绝对O(1)的操作</p>
<p>Is_numeric：判断一个变量是否是整数或数字字符串，也就是说除了整数型变量会返回true之外，对于字符串变量，如果形如”1234”，”1e4”等也会被判为true。这个时候会遍历字符串进行判断。</p>
<p>总结及建议</p>
<p><strong>通过对函数实现的原理分析和性能测试，我们总结出以下一些结论</strong></p>
<p>1． PHP的函数调用开销相对较大。</p>
<p>2． 函数相关信息保存在一个大的hash_table中，每次调用时通过函数名在hash表中查找，因此函数名长度对性能也有一定影响。</p>
<p>3． 函数返回引用没有实际意义</p>
<p>4． 内置php函数性能比用户函数高很多，尤其对于字符串类操作。</p>
<p>5． 类方法、普通函数、静态方法效率几乎相同，没有太大差异</p>
<p>6． 除去空函数调用的影响，内置函数和同样功能的C函数性能基本差不多。</p>
<p>7． 所有的参数传递都是采用引用计数的浅拷贝，代价很小。</p>
<p>8． 函数个数对性能影响几乎可以忽略</p>
<p><strong>因此，对于php函数的使用，有如下一些建议</strong></p>
<p>1． 一个功能可以用内置函数完成，尽量使用它而不是自己编写php函数。</p>
<p>2． 如果某个功能对性能要求很高，可以考虑用扩展来实现。</p>
<p>3． PHP函数调用开销较大，因此不要过分封装。有些功能，如果需要调用的次数很多本身又只用1、2行代码就行实现的，建议就不要封装调用了。</p>
<p>4． 不要过分迷恋各种设计模式，如上一条描述，过分的封装会带来性能的下降。需要考虑两者的权衡。PHP有自己的特点，切不可东施效颦，过分效仿java的模式。</p>
<p>5． 函数不宜嵌套过深，递归使用要谨慎。</p>
<p>6． 伪函数性能很高，同等功能实现下优先考虑。比如用isset代替array_key_exists</p>
<p>7． 函数返回引用没有太大意义，也起不到实际作用，建议不予考虑。</p>
<p>8． 类成员方法效率不比普通函数低，因此不用担心性能损耗。建议多考虑静态方法，可读性及安全性都更好。</p>
<p>9． 如不是特殊需要，参数传递都建议使用传值而不是传引用。当然，如果参数是很大的数组且需要修改时可以考虑引用传递。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpdo.net/index.php/php-function.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>mysql导入大文件的方法</title>
		<link>http://www.phpdo.net/index.php/mysql-import.html</link>
		<comments>http://www.phpdo.net/index.php/mysql-import.html#comments</comments>
		<pubDate>Mon, 12 Dec 2011 12:34:15 +0000</pubDate>
		<dc:creator>老张</dc:creator>
				<category><![CDATA[database]]></category>
		<category><![CDATA[mysql导入大文件的方法]]></category>

		<guid isPermaLink="false">http://www.phpdo.net/?p=1818</guid>
		<description><![CDATA[phpmyadmin导入mysql数据库时，mysql数据库最大只能导入2M，而要导入的数据远远大于2M，因此数据库不能导入，这时phpmyadmin数据库导入出错，并给出如下的错误信息： ]]></description>
			<content:encoded><![CDATA[<p>phpmyadmin导入mysql数据库时，mysql数据库最大只能导入2M，而要导入的数据远远大于2M，因此数据库不能导入，这时phpmyadmin数据库导入出错，并给出如下的错误信息：<br />
<code><br />
You probably tried to upload too large file. Please refer to documentation for ways to work around this limit.<br />
</code><br />
这时，我们可以使用下面的方法实现： </p>
<p>首先检查php.ini 配置文件中的以下三个地方，upload_max_filesize, mory_limit 和post_max_size，并且推荐修改的值要稍大于导入的巨大sql数据库文件；修改了以上三个在php.ini中的值以后，重启php环境(IIS)，再次导入时，虽然phpmyadmin还是显示导入最大限制：20,480 KB，但巨大的数据库文件已经被成功的导入了。</p>
<p>这种方法有时候不能奏效，但使用mysql的命令行模式好使，具体的详细步骤如下：<br />
<code><br />
a）在DOS下找到mysql的bin目录<br />
b)运行 ：>mysql -u root –p<br />
</code><br />
注意：上行中的root是本文作者的mysql的用户名，命令行会出现一个提示：<br />
<code><br />
Enter password:<br />
</code><br />
然后在其后输入你的mysql密码：<br />
<code><br />
Enter password: ****<br />
</code><br />
然后打回车，会出现一个提示：<br />
<code><br />
Welcome to MySQL monitor. Commands end with ; or g.<br />
Your MySQL connection id is 1<br />
Server version:5.1.41 Source distribution<br />
Type ‘help;’ or ‘h’ for help. Type ‘c’ to clear the current input statement.<br />
mysql><br />
</code><br />
此时出现的是提示您数据库已经可以试用，然后在mysql>后输入您要使用的数据库，比如我在我的mysql有一个空数据库名为testdb,然后我在mysql>的后边输入use testdb;即：<br />
<code><br />
mysql> use testdb;<br />
</code><br />
然后打回车，会出现：<br />
<code><br />
Database changed<br />
mysql><br />
</code><br />
后边输入你的mysql数据库文件所在，比如您的mysql文件是在D:\test.sql </p>
<p>那么此时您该输入source D:\test.sql也就是如下：<br />
<code><br />
Database changed<br />
mysql>source D:test.sql<br />
</code><br />
然后打回车，就会出现很多个:<br />
<code><br />
Query OK, 0 rows affected (0.00 sec)<br />
Query OK,5000 rows affected (1.55 sec)<br />
</code><br />
这样就成功的将mysql大数据库文件成功导入到数据库中。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpdo.net/index.php/mysql-import.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>左旋转字符串 [转]</title>
		<link>http://www.phpdo.net/index.php/rotating-string-left.html</link>
		<comments>http://www.phpdo.net/index.php/rotating-string-left.html#comments</comments>
		<pubDate>Sun, 11 Dec 2011 12:03:26 +0000</pubDate>
		<dc:creator>老张</dc:creator>
				<category><![CDATA[老张的碎嘴]]></category>
		<category><![CDATA[左旋转字符串 [转]]]></category>

		<guid isPermaLink="false">http://www.phpdo.net/?p=1808</guid>
		<description><![CDATA[第一节、左旋转字符串 题目描述： 定义字符串的左旋转操作：把字符串前面的若干个字符移动到字符串的尾部。如把字符串abcdef左旋转2位得到字符串cdefab。请实现字符串左旋转的函数，要求时间对长度为n的字符串操作的复杂度为O(n)，辅助内存为O(1)。 一听左旋，右旋之类的，便想到了红黑树中有关左旋，右旋的操作，不过，本题显然与此无关。 ok，整理了以下俩种思路： 思路一： //其实此思路一比较混乱，且代码也有问题，建议着重看思路二： 此思路一，引自网友zhedahht（http://zhedahht.blog.163.com/blog/#m）。 分析：如果不考虑时间和空间复杂度的限制，最简单的方法莫过于把这道题看成是把字符串分成前后两部分，通过旋转操作把这两个部分交换位置。 于是我们可以新开辟一块长度为n+1的辅助空间，把原字符串后半部分拷贝到新空间的前半部分，在把原字符串的前半部分拷贝到新空间的后半部分。不难看出，这种思路的时间复杂度是O(n)，需要的辅助空间也是O(n)。 因此，我们另寻思路，咱们试着把字符串看成有两段组成的，记为XY。左旋转相当于要把字符串XY变成YX。 我们先在字符串上定义一种翻转的操作，即翻转字符串中字符的先后顺序：把X翻转后记为XT,显然有(XT)T=X。 我们首先对X和Y两段分别进行翻转操作，这样就能得到XTYT。 接着再对XTYT进行翻转操作，得到(XTYT)T=(YT)T(XT)T=YX。正好是我们期待的结果。 分析到这里我们再回到原来的题目：我们要做的仅仅是把字符串分成两段， 第一段为前面m个字符，其余的字符分到第二段。再定义一个翻转字符串的函数，按照前面的步骤翻转三次就行了。时间复杂度和空间复杂度都合乎要求。 最初的代码如下（后来，我们将知道这段代码有几处错误，下文将具体阐述）： //引自：http://zhedahht.blog.163.com/blog/#m。 //2011.04.16声明： //1、在文章中引用任何人的思路，一律都会注明网友昵称。 //2、除非特别要求，否则不一定会再在文章醒目处注明任何人的链接。 //July、updated，2011.04.16。 #include "string.h" // Move the first n chars in a string to its end char* LeftRotateString(char* pStr, unsigned int n) { if(pStr != NULL) { int nLength = static_cast&#60;int&#62;(strlen(pStr)); if(nLength &#62; 0 &#124;&#124; [...]]]></description>
			<content:encoded><![CDATA[<p>第一节、左旋转字符串 </p>
<p>题目描述：</p>
<p>定义字符串的左旋转操作：把字符串前面的若干个字符移动到字符串的尾部。如把字符串abcdef左旋转2位得到字符串cdefab。请实现字符串左旋转的函数，要求时间对长度为n的字符串操作的复杂度为O(n)，辅助内存为O(1)。</p>
<p>一听左旋，右旋之类的，便想到了红黑树中有关左旋，右旋的操作，不过，本题显然与此无关。</p>
<p>ok，整理了以下俩种思路：</p>
<p>思路一： </p>
<p>//其实此思路一比较混乱，且代码也有问题，建议着重看思路二： </p>
<p>此思路一，引自网友zhedahht（http://zhedahht.blog.163.com/blog/#m）。 </p>
<p>分析：如果不考虑时间和空间复杂度的限制，最简单的方法莫过于把这道题看成是把字符串分成前后两部分，通过旋转操作把这两个部分交换位置。</p>
<p>于是我们可以新开辟一块长度为n+1的辅助空间，把原字符串后半部分拷贝到新空间的前半部分，在把原字符串的前半部分拷贝到新空间的后半部分。不难看出，这种思路的时间复杂度是O(n)，需要的辅助空间也是O(n)。</p>
<p>因此，我们另寻思路，咱们试着把字符串看成有两段组成的，记为XY。左旋转相当于要把字符串XY变成YX。 </p>
<p>我们先在字符串上定义一种翻转的操作，即翻转字符串中字符的先后顺序：把X翻转后记为XT,显然有(XT)T=X。</p>
<p>我们首先对X和Y两段分别进行翻转操作，这样就能得到XTYT。 </p>
<p>接着再对XTYT进行翻转操作，得到(XTYT)T=(YT)T(XT)T=YX。正好是我们期待的结果。</p>
<p>分析到这里我们再回到原来的题目：我们要做的仅仅是把字符串分成两段， </p>
<p>第一段为前面m个字符，其余的字符分到第二段。再定义一个翻转字符串的函数，按照前面的步骤翻转三次就行了。时间复杂度和空间复杂度都合乎要求。</p>
<p>最初的代码如下（后来，我们将知道这段代码有几处错误，下文将具体阐述）：<br />
<code><br />
//引自：http://zhedahht.blog.163.com/blog/#m。<br />
//2011.04.16声明：<br />
//1、在文章中引用任何人的思路，一律都会注明网友昵称。<br />
//2、除非特别要求，否则不一定会再在文章醒目处注明任何人的链接。<br />
//July、updated，2011.04.16。<br />
#include "string.h"<br />
// Move the first n chars in a string to its end<br />
char* LeftRotateString(char* pStr, unsigned int n)<br />
{<br />
if(pStr != NULL)<br />
    {<br />
int nLength = static_cast&lt;int&gt;(strlen(pStr));<br />
if(nLength &gt; 0 || n == 0 || n &gt; nLength)   //1、这里有问题，下文具体阐述。<br />
        {<br />
char* pFirstStart = pStr;<br />
char* pFirstEnd = pStr + n - 1;<br />
char* pSecondStart = pStr + n;<br />
char* pSecondEnd = pStr + nLength - 1;<br />
// reverse the first part of the string<br />
            ReverseString(pFirstStart, pFirstEnd);<br />
// reverse the second part of the strint<br />
            ReverseString(pSecondStart, pSecondEnd);<br />
// reverse the whole string<br />
            ReverseString(pFirstStart, pSecondEnd);<br />
        }<br />
    }<br />
return pStr;<br />
}<br />
// Reverse the string between pStart and pEnd<br />
void ReverseString(char* pStart, char* pEnd)<br />
{<br />
if(pStart == NULL || pEnd == NULL)     //2、这里也有问题，下文具体阐述。<br />
    {<br />
while(pStart &lt;= pEnd)<br />
        {<br />
char temp = *pStart;<br />
            *pStart = *pEnd;<br />
            *pEnd = temp;<br />
            pStart ++;<br />
            pEnd --;<br />
        }<br />
    }<br />
}<br />
</code><br />
思路二（请着重看此思路）：</p>
<p>先看下网友litaoye 的回复： </p>
<p>26.左旋转字符串<br />
跟panda所想，是一样的，即，<br />
以abcdef为例<br />
1. ab-&gt;ba<br />
2. cdef-&gt;fedc<br />
原字符串变为bafedc<br />
3. 整个翻转：cdefab<br />
  //只要俩次翻转，且时间复杂度也为O（n）。</p>
<p>在此，本人再奉献另外一种思路，即为本思路二： </p>
<p>abc defghi，要abc移动至最后<br />
abc defghi-&gt;def abcghi-&gt;def ghiabc</p>
<p>一俩指针，p1指向ch[0]，p2指向 ch[m-1]，p2每次移动m 的距离，p1 也跟着相应移动，每次移动过后，交换。</p>
<p>第一步，交换abc 和def ，abc defghi-&gt;def abcghi </p>
<p>第二步，交换abc 和 ghi，def abcghi-&gt;def ghiabc</p>
<p>整个过程，看起来，就是abc 一步一步 向后移动 </p>
<p>abc defghi<br />
def abcghi<br />
def ghi abc  </p>
<p>//最后的 复杂度是O（m+n） </p>
<p>各位读者注意了：由上述例子九个元素的序列abcdefghi，您已经看到，m=3时，p2恰好指到了数组最后一个元素，于是，上述思路没有问题。</p>
<p>但如果上面例子中i 的后面还有元素列?</p>
<p>即，如果是要左旋十个元素的序列：abcdefghij，ok，下面，就举这个例子，对abcdefghij序列进行左旋转操作：</p>
<p>如果abcdef ghij要变成defghij abc：<br />
<code><br />
  abcdef ghij<br />
1. def abc ghij<br />
2. def ghi abc j<br />
3. def ghi ab jc<br />
4. def ghi a j bc<br />
5. def ghi j abc<br />
</code><br />
下面，再针对上述过程，画个图清晰说明下，如下所示：</p>
<p>updated：（其实，网友大肥也提出了此思路，特此再总结一下上述思路二）然后，你就自然而然的发现，下述的思路及代码是有局限性的，即用下述思路处理最上面的那个abcdefghi 还可以，但若要处理十个元素的序列，如abcdefghij 则不行了，所以，我们淘汰此原来写的代码：</p>
<p>1.给2个指针p1和p2,p1=p2=ch[0]; </p>
<p>2.移动p2到ch[m-1]假设之间的距离是m<br />
<code><br />
  while( p1 != p2 )<br />
  {<br />
    swap( *p1, *p2 );<br />
        p1++;<br />
     if( p2+1 )<br />
       p2++;<br />
  }<br />
</code><br />
你也能发现，下述的总结，也是错误的，同样，我们也淘汰它：这样我们可以做一个模拟的过程，abcdefgh 我们要移动abc到最后，那么有：<br />
<code><br />
abc def ghij<br />
//最开始时，p1在a，p2在d<br />
=&gt; def abc ghij<br />
//abc与def交换完成后，p1++，p1在a，p2++，p2在g，<br />
=&gt; def ghi abcj<br />
//abc 与 ghi交换完成后，p1++，p1在a，p2++，p2在j<br />
=&gt; def ghi jbca  //a与j交换，p1++，在b，p2在a<br />
=&gt; def ghi jacb  //b与a交换，p1++，在c，p2在b<br />
=&gt; def ghi jabc  //c与b交换，完成。<br />
</code><br />
可以看到，上述最后的三步，p2已经没动了。</p>
<p>时间复杂度就是O(n+m) = O(n), swap也就只要O(1)的空间就好！</p>
<p>那么，我们该如何思考这一问题列?或者，怎么总结此思路二列?</p>
<p>ok，咱们来好好彻底总结一下此思路二（就4条语句，请仔细阅读）：</p>
<p>1、首先让p1=ch[0]，p2=ch[m-1]，即让p1，p2相隔m的距离；</p>
<p>2、通过不断交换*p1与*p2，然后p1++，p2++，直到p2+1所指处越界，转到3。</p>
<p>3、此时p2+1已经越界，无法再后移m的距离，所以保持p1不动，</p>
<p>4、p2与p2-1交换，p2-1与p2-2交换，直到p2-m=p1，此时，p2-m+1与p1交换。</p>
<p>   //上述第4行，即相当于执行第3行语句之后，p2所指的元素j步步前移，直到形成jabc的序列。</p>
<p>即上述最后一步，第4步过程为：abcj-&gt;abjc-&gt;ajbc-&gt;jabc。</p>
<p>我编写的此思路二的伪码如下（注，信手而写，不负责结果正确）：<br />
<code><br />
//July，此思路二的伪码如下： //下文已经编写出完整代码，且此伪码也是有问题的。<br />
int rorate(int* p1,int* p2)<br />
{<br />
    int ch[n]=new int[];<br />
    p1=p2=ch[0];<br />
    for(int k=1;k&lt;=m;k++)<br />
    {<br />
        p2++;   //p2后移m个单位<br />
    }<br />
    while((p2++)!=NULL)<br />
    {<br />
        swap(*p1,*p2);<br />
        p1++;<br />
        if(p2+1)<br />
            p2++;<br />
        else<br />
            break;   //此处，我让之跳出来处理。<br />
    }<br />
    for(r=m+1;r&gt;0;r--)<br />
    {<br />
        //只要p2-m!=p1,p2就不断继续--，然后与前面的元素交换。<br />
                  //....<br />
        //相当于j前移到abc的前面，最终序列为jabc。<br />
    }<br />
}<br />
</code><br />
于是，根据上述思路，及伪码，不难写出下述代码（已测试正确）：<br />
<code><br />
#include &lt;iostream&gt;<br />
#include &lt;string&gt;<br />
using namespace std;<br />
void swap(char* a,char* b)  //交换<br />
{<br />
char temp =*a;<br />
    *a = *b;<br />
    *b = temp;<br />
}<br />
//July、颜沙，2011.04.16。<br />
void rotate(string &amp;str, int m)<br />
{<br />
if (str.length() == 0 || m &lt; 0)<br />
return;<br />
int p1 = 0, p2 = 0;<br />
int n = str.length();<br />
// 处理m大于n<br />
    m = m % n;<br />
int t = m;<br />
// p2初始位置<br />
while(t--)<br />
        p2++;<br />
// 循环直至p2到达字符串末尾<br />
while(true)<br />
    {<br />
        swap(str[p1], str[p2]);<br />
        p1++;<br />
if (p2 &lt; n - 1)<br />
            p2++;<br />
else<br />
break;<br />
    }<br />
//重点，都在下述几行。<br />
//处理尾部，r为尾部循环左移次数<br />
int r=m+1;<br />
while (r--)<br />
    {<br />
int i=p2;<br />
while (i&gt;p1)<br />
        {<br />
            swap(str[i],str[i-1]);<br />
            i--;<br />
        }<br />
        swap(str[i],str[p1]);<br />
    }<br />
}<br />
int main()<br />
{<br />
    string ch="abcdefghij";<br />
    rotate(ch,3);<br />
    cout&lt;&lt;ch&lt;&lt;endl;<br />
return 0;<br />
}<br />
</code><br />
或者如颜沙所说：最初的那个左旋转九个元素abcdefghi的思路在末尾会出现问题的（如果p2后面有元素就不能这么变，例如如果是处理十个元素，abcdefghij 列?对的，就是这个意思），他的解决办法是（跟我上面的总结，是一个道理）： </p>
<p>令s=m-n%m，然后将最后m个单位循环左移m-s处理尾巴。解释：n为总的元素个数，k为p1或p2移动距离加1，m是需要循环左移单元<br />
<code><br />
举例 m = 3;<br />
abc def ghi j //最开始时，p1在a，p2在d<br />
=&gt;def abc ghi j  //p1+3在a，p2+3在g<br />
=&gt;def ghi abc j  //p1+3在a, p2+3在j<br />
=&gt;def ghi jbc a  //最后m个单元循环左移m-s个单位，即3-11%3=1<br />
=&gt;def ghi j abc  //即a左移到 bc的左边去。<br />
</code><br />
实质是abc在处理尾巴问题做了一些循环，还要补充一些循环使得abc的相对位置保持不变。</p>
<p>updated： </p>
<p>方法一：<br />
def ghi abc jk<br />
当p1指向a，p2指向j时，由于p2+m越界，那么此时p1，p2不要变<br />
这里p1之后（abcjk)就是尾巴，处理尾巴只需将j,k移到abc之前，得到最终序列，即为上面总结的思路二。</p>
<p>方法二：<br />
def ghi abc jk<br />
当p1指向a，p2指向j时，那么交换p1和p2，p1++，p2++<br />
此时为 def ghi jbc ak<br />
p1指向b，p2指向k，继续上面步骤得<br />
def ghi jkc ab<br />
p1指向c，p2指向b，p1和p2之间（cab)也就是尾巴，那么处理尾巴（cab)需要循环左移一定次数</p>
<p>根据方案二，不难写出下述代码（已测试正确）：<br />
<code><br />
#include &lt;iostream&gt;<br />
#include &lt;string&gt;<br />
using namespace std;<br />
//颜沙，思路二之方案二，<br />
//July、updated，2011.04.16。<br />
void rotate(string &amp;str, int m)<br />
{<br />
if (str.length() == 0 || m &lt; 0)<br />
return;<br />
int p1 = 0, p2 = 0;<br />
int n = str.length();<br />
// 处理m大于n<br />
    m = m % n;<br />
int t = m;<br />
// p2初始位置<br />
while(t--)<br />
        p2++;<br />
// 循环直至p2到达字符串末尾<br />
while(true)<br />
    {<br />
        swap(str[p1], str[p2]);<br />
        p1++;<br />
if (p2 &lt; n - 1)<br />
            p2++;<br />
else<br />
break;<br />
    }<br />
// 处理尾部，r为尾部循环左移次数<br />
int r = m - n % m;<br />
while (r--)<br />
    {<br />
int i = p1;<br />
char temp = str[p1];<br />
while (i &lt; p2)<br />
        {<br />
            str[i] = str[i+1];<br />
            i++;<br />
        }<br />
        str[p2] = temp;<br />
    }<br />
}<br />
int main()<br />
{<br />
    string ch="abcdefghij";<br />
    rotate(ch,3);<br />
    cout&lt;&lt;ch&lt;&lt;endl;<br />
return 0;<br />
}<br />
</code><br />
注意：上文中都是假设m&lt;n，且如果鲁棒点的话令m=m%n，这样m允许大于n。另外，各位要记得处理指针为空的情况。</p>
<p>总结：思路二，基本上没有什么问题，相比之下，也胜于思路一。但答案中既然给出了思路一，且代码也存在不少问题，那只好先抓着思路一的代码不放，把错误纠正过来，再说。下面，我将具体针对思路一，具体而深入的阐述。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpdo.net/index.php/rotating-string-left.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>国内两大微博：腾讯和新浪对比</title>
		<link>http://www.phpdo.net/index.php/weibo.html</link>
		<comments>http://www.phpdo.net/index.php/weibo.html#comments</comments>
		<pubDate>Sat, 10 Dec 2011 00:42:37 +0000</pubDate>
		<dc:creator>老张</dc:creator>
				<category><![CDATA[老张的碎嘴]]></category>
		<category><![CDATA[国内两大微博：腾讯和新浪对比]]></category>

		<guid isPermaLink="false">http://www.phpdo.net/?p=1442</guid>
		<description><![CDATA[在国外，烧了投资人无数银子的SNS公司终于一个接一个地上市；在国内新浪、腾讯、搜狐、甚至百度都纷纷调整战略将微博作为他们一个重要的战略布局。 对于这些巨头，微博要么是巩固自己帝国版图的战略性防御武器，要么是追赶对手甚至反戈一击的绝好机会。 对于媒体人或者那些意见领袖们，微博是他们的扩音器，同时他们更希望微博日后成为推动社会进步的加速器。 对于大量的草根用户，在他们厌倦了传统媒体上对权威的“90度仰视”和网络中对同伴的“0度交流”之后，微博提供给他们了一个独特的45度视角，使他们在聆听的同时还可以有效的表达。 所以，几乎是一夜之间微博红遍中国大江南北。在这样一个市场面前，创业者没有理由不激动。 问题是，微博（SNS平台）对于创业者到底意味着什么? Linkedin创始人Reid Hoffman最近的一个观点可能代表了美国资本市场的普遍看法：“if Web 1.0 involved“go search, get data”and some limited interactivity;and if Web 2.0involves “real identities”and“real relationships”，then Web 3.0 willbe “real identities generating massive amounts of data.”。 这就好像在说现在是最好的时代也是最坏的时代。 面对如此大量的用户产生的内容，创业者第一次有机会在创业的第一天就拥有一个上亿用户的平台，以及这个平台上属于每个用户的独特数据。但与此同时，如果不对这些内容加以分析利用，互联网的效率就会被“信息过载”严重降低。这是一个刚性需求。但创业者担心的却是这些社会化平台本身–他们是否开放？他们现在有多么开放？他们未来会多开放？我们可以从很多维度讨论这个问题：企业战略，社会趋势，技术发展等等。 但创业者最关心的却是这些平台提供的API（应用程序接口）。毕竟，内容属于平台，而API是其他人获取这些内容几乎唯一的合法途径。API种类是否丰富，数据是否完整，使用时限制又有多少，直接影响了创业点子的可行性。 因此，我们就从以上几个方面对目前国内最流行的两个微博平台，腾讯和新浪，做一个简单的比较。 API多样性 开发者使用一个开放平台最关心的是“这个平台提供了哪些API”以及“这些API又能实现什么功能”。新浪目前开放了近100个API接口，和腾讯相比，开放的方式更接近twitter。如果我们仔细的对比一下新浪和twitter的API，我们就会发现，双方不仅在数量上相当，在功能上新浪几乎提供了所有twitter开放的服务。 相比之下，腾讯API的种类就少很多，目前只有60个左右。进一步来看，我们可以将微博平台提供的服务大致分为：公共内容，用户内容，用户关系链以及其他辅助功能（例如搜索）。 在公共内容上面，腾讯和新浪都提供了获取公共微博和热门话题的接口。但新浪的热门话题接口更加丰富，包括了每周，每日和每小时的热门话题。而腾讯只提供了一个“话题热榜”接口，返回当前最流行的话题。 在“用户内容”上，两个平台的差别更加明显。新浪API接口以用户为中心，腾讯则更偏重提供基础数据。例如，对于微博的转发和评论，新浪直接提供了API可以获取一个用户发出和收到的评论。而腾讯只提供了由”获取一条微博所有评论“的API。这意味着，在新浪微博上通过一个API请求就可以获得的”某个用户收到的评论“，在腾讯平台上，开发者需要先获得用户发表的微博列表，然后再拿着每条微博向腾讯再次请求其所有评论。 不仅如此，目前为之腾讯仍未开放“获取一个用户所发表的评论”的接口。 对于”用户关系链“的开放，腾讯和新浪差别不大，第三方都可以拿到一个用户的粉丝和好友列表。由于腾讯微博本身提供了”特别收听“功能，通过其API还可以获得一个用户”特别收听列表“。 最后，在”辅助功能“上面，双方都提供了”好友推荐“和比较完整的搜索服务（搜索用户，搜索微博），但新浪目前还支持获得一个用户”可能感兴趣的标签“，这个API为做基于微博的推荐服务提供了有效的参考信息。 API的数量和种类是多样性的一个方面，其另外一个方面则是每个API的功能性。与腾讯相比，新浪的API功能更加丰富。以”获取用户的微博“这个接口为例，新浪接受的参数如下： 请求参数 必选       类型及范围       说明 source [...]]]></description>
			<content:encoded><![CDATA[<p>在国外，烧了投资人无数银子的SNS公司终于一个接一个地上市；在国内新浪、腾讯、搜狐、甚至百度都纷纷调整战略将微博作为他们一个重要的战略布局。</p>
<p>对于这些巨头，微博要么是巩固自己帝国版图的战略性防御武器，要么是追赶对手甚至反戈一击的绝好机会。</p>
<p>对于媒体人或者那些意见领袖们，微博是他们的扩音器，同时他们更希望微博日后成为推动社会进步的加速器。</p>
<p>对于大量的草根用户，在他们厌倦了传统媒体上对权威的“90度仰视”和网络中对同伴的“0度交流”之后，微博提供给他们了一个独特的45度视角，使他们在聆听的同时还可以有效的表达。</p>
<p>所以，几乎是一夜之间微博红遍中国大江南北。在这样一个市场面前，创业者没有理由不激动。</p>
<p>问题是，微博（SNS平台）对于创业者到底意味着什么?</p>
<p>Linkedin创始人Reid Hoffman最近的一个观点可能代表了美国资本市场的普遍看法：“if Web 1.0 involved“go search, get data”and some limited interactivity;and if Web 2.0involves “real identities”and“real relationships”，then Web 3.0 willbe “real identities generating massive amounts of data.”。</p>
<p>这就好像在说现在是最好的时代也是最坏的时代。</p>
<p>面对如此大量的用户产生的内容，创业者第一次有机会在创业的第一天就拥有一个上亿用户的平台，以及这个平台上属于每个用户的独特数据。但与此同时，如果不对这些内容加以分析利用，互联网的效率就会被“信息过载”严重降低。这是一个刚性需求。但创业者担心的却是这些社会化平台本身–他们是否开放？他们现在有多么开放？他们未来会多开放？我们可以从很多维度讨论这个问题：企业战略，社会趋势，技术发展等等。</p>
<p>但创业者最关心的却是这些平台提供的API（应用程序接口）。毕竟，内容属于平台，而API是其他人获取这些内容几乎唯一的合法途径。API种类是否丰富，数据是否完整，使用时限制又有多少，直接影响了创业点子的可行性。</p>
<p>因此，我们就从以上几个方面对目前国内最流行的两个微博平台，腾讯和新浪，做一个简单的比较。</p>
<p>API多样性<br />
开发者使用一个开放平台最关心的是“这个平台提供了哪些API”以及“这些API又能实现什么功能”。新浪目前开放了近100个API接口，和腾讯相比，开放的方式更接近twitter。如果我们仔细的对比一下新浪和twitter的API，我们就会发现，双方不仅在数量上相当，在功能上新浪几乎提供了所有twitter开放的服务。</p>
<p>相比之下，腾讯API的种类就少很多，目前只有60个左右。进一步来看，我们可以将微博平台提供的服务大致分为：公共内容，用户内容，用户关系链以及其他辅助功能（例如搜索）。<br />
在公共内容上面，腾讯和新浪都提供了获取公共微博和热门话题的接口。但新浪的热门话题接口更加丰富，包括了每周，每日和每小时的热门话题。而腾讯只提供了一个“话题热榜”接口，返回当前最流行的话题。<br />
在“用户内容”上，两个平台的差别更加明显。新浪API接口以用户为中心，腾讯则更偏重提供基础数据。例如，对于微博的转发和评论，新浪直接提供了API可以获取一个用户发出和收到的评论。而腾讯只提供了由”获取一条微博所有评论“的API。这意味着，在新浪微博上通过一个API请求就可以获得的”某个用户收到的评论“，在腾讯平台上，开发者需要先获得用户发表的微博列表，然后再拿着每条微博向腾讯再次请求其所有评论。</p>
<p>不仅如此，目前为之腾讯仍未开放“获取一个用户所发表的评论”的接口。</p>
<p>对于”用户关系链“的开放，腾讯和新浪差别不大，第三方都可以拿到一个用户的粉丝和好友列表。由于腾讯微博本身提供了”特别收听“功能，通过其API还可以获得一个用户”特别收听列表“。</p>
<p>最后，在”辅助功能“上面，双方都提供了”好友推荐“和比较完整的搜索服务（搜索用户，搜索微博），但新浪目前还支持获得一个用户”可能感兴趣的标签“，这个API为做基于微博的推荐服务提供了有效的参考信息。</p>
<p>API的数量和种类是多样性的一个方面，其另外一个方面则是每个API的功能性。与腾讯相比，新浪的API功能更加丰富。以”获取用户的微博“这个接口为例，新浪接受的参数如下：</p>
<p>请求参数</p>
<p><strong>必选</strong>       <strong>类型及范围</strong>       <strong>说明</strong></p>
<p>source   true                     string</p>
<p>申请应用时分配的AppKey，调用接口时候代表应用的唯一身份。（采用OAuth授权方式不需要此参数）</p>
<p>:id           false                   int64/string</p>
<p>根据用户ID(int64)或者微博昵称(string)返回指定用户的最新微博消息列表。该参数为REST风格参数，参见注意事项</p>
<p>user_id  false                   int64</p>
<p>用户ID，主要是用来区分用户ID跟微博昵称。当微博昵称为数字导致和用户ID产生歧义，特别是当微博昵称和用户ID一样的时候，建议使用该参数</p>
<p>screen_name false        string</p>
<p>微博昵称，主要是用来区分用户UID跟微博昵称，当二者一样而产生歧义的时候，建议使用该参数</p>
<p>since_id    false               int64</p>
<p>若指定此参数，则只返回ID比since_id大（即比since_id发表时间晚的）的微博消息。</p>
<p>max_id    false                int64</p>
<p>若指定此参数，则返回ID小于或等于max_id的微博消息</p>
<p>count      false                  int，默认值20，最大值200。</p>
<p>指定每页返回的记录条数。</p>
<p>page        false                   int，默认值1。</p>
<p>页码。注意：最多返回200条分页内容。</p>
<p>如果:id、user_id、screen_name三个参数均未指定，则返回当前登录用户最近发表的微博消息列表。</p>
<p>base_app  false              int</p>
<p>是否基于当前应用来获取数据。1为限制本应用微博，0为不做限制。</p>
<p>feature       false              int</p>
<p>微博类型，0全部，1原创，2图片，3视频，4音乐. 返回指定类型的微博信息内容。</p>
<p>与之相比，腾讯的接口就更原始一些：</p>
<p>请求参数<br />
必选    类型及范围    说明<br />
oauth    true    string    oauth标准参数<br />
Format    false    string    返回结果的格式：xml或者json<br />
Pageflag    false    int    分页标示，0表示第一页，1表示向下翻，2表示向上翻<br />
Pagetime    false    int    本页起始时间，第一页填0，继续翻页：填上一次请求返回的最后一条记录时间<br />
Reqnum    false    int    每次请求记录的条数<br />
LastId    false    int64    第一页时填0,继续向下翻页，填上一次请求返回的最后一条记录ID，翻页用<br />
Name    true    string    你需要读取的用户的用户名</p>
<p>我们可以看出，腾讯的接口只提供了翻页的功能，而新浪则提供了微博过滤。不仅是”获取微博“这个接口，新浪的大部分API都具备一定程度的信息过滤的能力，而腾讯的大部分接口只提供基本数据。作为第三方的开发者，API接口功能的丰富不仅简化了开发，也降低了某些应用程序超过API请求限制的风险。</p>
<p>数据完整性</p>
<p>数据完整性是指当开发者请求某种数据时，开放平台是否对返回数据的数量有所限制。它最能反映一个平台的开放程度。遗憾的是，从这个意义上讲，不论新浪或者腾讯目前为止都没有做到真正的开放。以获取一个用户的”粉丝列表“为例，我们可以看到新浪，腾讯以及Twitter之间的差别。</p>
<p>Twitter是一个真正开放的平台，开发者可以通过API获取任意用户的完整粉丝列表。虽然一次请求最多返回100个粉丝的详细信息，但在Twitter我们可以通过发送多次请求获得一个完整的粉丝名单。再看新浪，对于一般授权用户，最多只能获得5000个最新粉丝信息，但和twitter相比，新浪允许每次请求最多返回200个粉丝。</p>
<p>不过，新浪和twitter为开发者还提供了专门的”社交图谱“接口，一次请求最多获取一个用户5000个粉丝的id。只是，新浪仍然将能获取的粉丝总数设定在5000，而twitter还是一如既往的开放。</p>
<p>至于腾讯，其API文档并没有限定获取用户粉丝的数量，但一次API请求最多只能取得30个粉丝信息，而且也没有提供类似”社会图谱“的接口。在这种限制下，想在腾讯微博平台为一个拥有几十万粉丝的用户构建”社交图谱“，难度可想而知。</p>
<p>请求限制</p>
<p>很多开发者子在开放平台上抱怨最多不是API的功能多少，而是每个平台对于API请求的限制了。但是所有的开放平台（不论是twitter，linkedin还是facebook）都会一定程度上限制其开发者对自己资源的使用。这与”开放“的策略无关，更多的是基于系统安全性的考虑。因此各个平台对API的限制策略基本相同，例如，新浪给与普通授权开发者每小时每ip最多1万次API请求，单个用户每小时150次请求（腾讯和新浪详细访问)。</p>
<p>真正的问题不在于一个平台给与基本授权应用多少请求配额，而在于当一个应用因为配额受到限制的时候，这些平台能以什么样的方式去为应用程序解决这个问题。一个平台只有设计一个公开公平的规则，它才能真正消除开发者对其开放性的怀疑。<br />
通过上面的分析，我们可以清晰的看到新浪是国内目前最接近twitter的微博平台（从规模和开放性两个方面），copycat这一次复制的恰到好处。</p>
<p>腾讯的微博和twitter相比，完全是另外一个产品。虽然它包含了腾讯对微博和开放平台自己的理解和计划，但目前只适合支持以”用户驱动“的基础应用。对于“数据驱动”的复杂应用，其平台的接口暂时还远不能满足开发者的需要。</p>
<p>注：本文由深圳乐荐网络科技有限公司联合创始人邵宝麟供稿，哥伦比亚大学计算机在读博士，2007年获得华中科技大学软件工程学士学位。曾在印度Infosys SETLab和美国IBM T.J Watson研究中心进行关于“下一代高性能分布计算”的研究。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpdo.net/index.php/weibo.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>10种经典的错误提示信息</title>
		<link>http://www.phpdo.net/index.php/mistake.html</link>
		<comments>http://www.phpdo.net/index.php/mistake.html#comments</comments>
		<pubDate>Fri, 09 Dec 2011 01:08:03 +0000</pubDate>
		<dc:creator>老张</dc:creator>
				<category><![CDATA[老张的碎嘴]]></category>
		<category><![CDATA[10种经典的错误提示信息]]></category>

		<guid isPermaLink="false">http://www.phpdo.net/?p=1444</guid>
		<description><![CDATA[对于编程来说，没有错误是美好的一天。但不幸的是，这种情况比你希望的要少得多。最近你见过下面这些有趣的原始错误信息吗？ 从难以理解的字母数字混合形式，到令人惊讶的有趣形式，错误信息一直用其独有的计算机形式告知我们，而我们永远也无法真正理解。循环逻辑、微类型以及突然闪现的出乎意料的幽默，使得错误信息成为我们时代的芝诺悖论，以及任何PC用户都会频繁遇到的问题。 1.错误：没有错误 让我们从最经典的开始：不是错误提示的提示信息。但愿所有的错误信息都是这种无害信息。 2.没有删除空间 这是表示人类逻辑和计算机逻辑冲突的一种错误提示信息。执行删除操作之前判断能够执行的条件对Windows系统很重要，因为可能存在没有足够空间用来执行删除操作这种情况，这对普通用户来说很难理解。 3.循环错误 当计算机试图提示一个错误产生了另一个新错误时，你应该知道系统出现了严重问题。 4.完全递归错误 当一些错误持续产生新错误，就好像计算机把你带到视频游戏中。其带来的挑战是：你能足够快地按Enter键来让你的电脑重新恢复吗？(提示：你不能) 5.视频游戏错误 基于窗口的PC偶尔会向当前用户提示错误信息，表示所做的操作超出了能力范围，但它并不是唯一这样做的机器。游戏控制台只会同样混乱。 6.Google Chrome浏览器错误页面 如果没什么其他的东西，错误信息这几年已经非常人性化了。Chrome浏览器的网页会提示错误，上面有一个失望的表情和错误信息，这正快速成为我的新的死机蓝屏标志。 7.Google Reader错误 总体来说，Google更倾向于提示有趣的错误信息。这个经典的Google Reader错误简洁、明快、切题并且拥有版权。 8.404（页面不存在）错误 网络中心时代最经典的错误提示信息之一是404错误。大量的网站都出现过这种经典的“页面不存在”提示，就像例子中游戏卖家Dawdle网站显示的那样。 9.Grooveshark网站的停机错误信息 有时候，仅仅一副有趣的图片还不够。在这里，音乐流媒体服务Grooveshark非常友好地为停机做出了解释，错误提示信息的插图和内容涉及一些中国的投资者以及一头名为Pickles的饥饿的大熊猫。 10.The Tumbl Tumbeasts 去年年底一连串的停机之后，Webcomic The Oatmeal建议Tumblr采用跟Twitter的宕机画面类似的自己的错误提示。最精彩的部分呢？Tumblr正在使用。]]></description>
			<content:encoded><![CDATA[<p>对于编程来说，没有错误是美好的一天。但不幸的是，这种情况比你希望的要少得多。最近你见过下面这些有趣的原始错误信息吗？</p>
<p>从难以理解的字母数字混合形式，到令人惊讶的有趣形式，错误信息一直用其独有的计算机形式告知我们，而我们永远也无法真正理解。循环逻辑、微类型以及突然闪现的出乎意料的幽默，使得错误信息成为我们时代的芝诺悖论，以及任何PC用户都会频繁遇到的问题。</p>
<p><strong>1.错误：没有错误</strong></p>
<p>让我们从最经典的开始：不是错误提示的提示信息。但愿所有的错误信息都是这种无害信息。</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/12/1.jpg"><img class="aligncenter size-full wp-image-1791" title="1" src="http://www.phpdo.net/wp-content/uploads/2011/12/1.jpg" alt="" width="274" height="192" /></a></p>
<p><strong>2.没有删除空间</strong></p>
<p>这是表示人类逻辑和计算机逻辑冲突的一种错误提示信息。执行删除操作之前判断能够执行的条件对Windows系统很重要，因为可能存在没有足够空间用来执行删除操作这种情况，这对普通用户来说很难理解。</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/12/2.jpg"><img class="aligncenter size-full wp-image-1793" title="2" src="http://www.phpdo.net/wp-content/uploads/2011/12/2.jpg" alt="" width="330" height="147" /></a></p>
<p><strong>3.循环错误</strong></p>
<p>当计算机试图提示一个错误产生了另一个新错误时，你应该知道系统出现了严重问题。</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/12/3.jpg"><img class="aligncenter size-full wp-image-1794" title="3" src="http://www.phpdo.net/wp-content/uploads/2011/12/3.jpg" alt="" width="256" height="139" /></a></p>
<p><strong>4.完全递归错误</strong></p>
<p>当一些错误持续产生新错误，就好像计算机把你带到视频游戏中。其带来的挑战是：你能足够快地按Enter键来让你的电脑重新恢复吗？(提示：你不能)</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/12/4.jpg"><img class="aligncenter size-full wp-image-1795" title="4" src="http://www.phpdo.net/wp-content/uploads/2011/12/4.jpg" alt="" width="500" height="406" /></a></p>
<p><strong>5.视频游戏错误</strong></p>
<p>基于窗口的PC偶尔会向当前用户提示错误信息，表示所做的操作超出了能力范围，但它并不是唯一这样做的机器。游戏控制台只会同样混乱。</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/12/5.jpg"><img class="aligncenter size-full wp-image-1796" title="5" src="http://www.phpdo.net/wp-content/uploads/2011/12/5.jpg" alt="" width="500" height="406" /></a></p>
<p><strong>6.Google Chrome浏览器错误页面</strong></p>
<p>如果没什么其他的东西，错误信息这几年已经非常人性化了。Chrome浏览器的网页会提示错误，上面有一个失望的表情和错误信息，这正快速成为我的新的死机蓝屏标志。</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/12/6.jpg"><img class="aligncenter size-full wp-image-1797" title="6" src="http://www.phpdo.net/wp-content/uploads/2011/12/6.jpg" alt="" width="500" height="406" /></a></p>
<p><strong>7.Google Reader错误</strong></p>
<p>总体来说，Google更倾向于提示有趣的错误信息。这个经典的Google Reader错误简洁、明快、切题并且拥有版权。</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/12/7.jpg"><img class="aligncenter size-full wp-image-1798" title="7" src="http://www.phpdo.net/wp-content/uploads/2011/12/7.jpg" alt="" width="500" height="406" /></a></p>
<p><strong>8.404（页面不存在）错误</strong></p>
<p>网络中心时代最经典的错误提示信息之一是404错误。大量的网站都出现过这种经典的“页面不存在”提示，就像例子中游戏卖家Dawdle网站显示的那样。</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/12/8.jpg"><img class="aligncenter size-full wp-image-1799" title="8" src="http://www.phpdo.net/wp-content/uploads/2011/12/8.jpg" alt="" width="500" height="406" /></a></p>
<p><strong>9.Grooveshark网站的停机错误信息</strong></p>
<p>有时候，仅仅一副有趣的图片还不够。在这里，音乐流媒体服务Grooveshark非常友好地为停机做出了解释，错误提示信息的插图和内容涉及一些中国的投资者以及一头名为Pickles的饥饿的大熊猫。</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/12/9.jpg"><img class="aligncenter size-full wp-image-1800" title="9" src="http://www.phpdo.net/wp-content/uploads/2011/12/9.jpg" alt="" width="500" height="406" /></a></p>
<p><strong>10.The Tumbl Tumbeasts</strong></p>
<p>去年年底一连串的停机之后，Webcomic The Oatmeal建议Tumblr采用跟Twitter的宕机画面类似的自己的错误提示。最精彩的部分呢？Tumblr正在使用。</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/12/10.jpg"><img class="aligncenter size-full wp-image-1801" title="10" src="http://www.phpdo.net/wp-content/uploads/2011/12/10.jpg" alt="" width="500" height="406" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpdo.net/index.php/mistake.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>LAMP网站架构方案分析</title>
		<link>http://www.phpdo.net/index.php/lamp-web.html</link>
		<comments>http://www.phpdo.net/index.php/lamp-web.html#comments</comments>
		<pubDate>Thu, 08 Dec 2011 11:58:48 +0000</pubDate>
		<dc:creator>老张</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[LAMP网站架构方案分析]]></category>

		<guid isPermaLink="false">http://www.phpdo.net/?p=1467</guid>
		<description><![CDATA[LAMP（Linux-Apache-MySQL-PHP）网站架构是目前国际流行的Web框架，该框架包括：Linux操作系统，Apache网络服务器，MySQL数据库，Perl、PHP或者Python编程语言，所有组成产品均是开源软件，是国际上成熟的架构框架，很多流行的商业应用都是采取这个架构，和Java/J2EE架构相比，LAMP具有Web资源丰富、轻量、快速开发等特点，微软的.NET架构相比，LAMP具有通用、跨平台、高性能、低价格的优势，因此LAMP无论是性能、质量还是价格都是企业搭建网站的首选平台。 对于大流量、大并发量的网站系统架构来说，除了硬件上使用高性能的服务器、负载均衡、CDN等之外，在软件架构上需要重点关注下面几个环节：使用高性能的操作系统（OS）、高性能的网页服务器（Web Server）、高性能的数据库（Databse）、高效率的编程语言等。下面我将从这几点对其一一讨论。 操作系统 Linux操作系统有很多个不同的发行版，如Red Hat Enterprise Linux、SUSE Linux Enterprice、Debian、Ubuntu、CentOS等，每一个发行版都有自己的特色，比如RHEL的稳定，Ubuntu的易用，基于稳定性和性能的考虑，操作系统选择CentOS（Community ENTerprise Operating System）是一个理想的方案。 CentOS（Community ENTerprise Operating System）是Linux发行版之一，是RHEL/Red Hat Enterprise Linux的精简免费版，和RHEL为同样的源代码，不过，RHEL和SUSE LE等企业版，提供的升级服务均是收费升级，无法免费在线升级，因此要求免费的高度稳定性的服务器可以用CentOS替代Red Hat Enterprise Linux使用。 &#160; &#160; Web服务器、缓存和PHP加速 Apache是LAMP架构最核心的Web Server，开源、稳定、模块丰富是Apache的优势。但Apache的缺点是有些臃肿，内存和CPU开销大，性能上有损耗，不如一些轻量级的Web服务器（例如nginx）高效，轻量级的Web服务器对于静态文件的响应能力来说远高于Apache服务器。 Apache做为Web Server是负载PHP的最佳选择，如果流量很大的话，可以采用nginx来负载非PHP的Web请求。nginx是一个高性能的HTTP和反向代理服务器，Nginx以它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。Nginx不支持PHP和CGI等动态语言，但支持负载均衡和容错，可和Apache配合使用，是轻量级的HTTP服务器的首选。 Web服务器的缓存也有多种方案，Apache提供了自己的缓存模块，也可以使用外加的Squid模块进行缓存，这两种方式均可以有效的提高Apache的访问响应能力。Squid Cache是一个Web缓存服务器，支持高效的缓存，可以作为网页服务器的前置cache服务器缓存相关请求来提高Web服务器的速度，把Squid放在Apache的前端来缓存Web服务器生成的动态内容，而Web应用程序只需要适当地设置页面实效时间即可。如访问量巨大则可考虑使用memcache作为分布式缓存。 PHP的加速使用eAccelerator加速器，eAccelerator是一个自由开放源码PHP加速器，优化和动态内容缓存，提高了性能PHP脚本的缓存性能，使得PHP脚本在编译的状态下，对服务器的开销几乎完全消除。它还有对脚本起优化作用，以加快其执行效率。使PHP程序代码执效率能提高1-10倍。 具体的解决方案有以下几种： 1、squid + Apache + PHP + eAccelerator 使用Apache负载PHP，使用squid进行缓存，html或图片的请求可以直接由squid返回给用户。很多大型网站都采用这种架构。 2、nginx/Apache + PHP（fastcgi） + eAccelerator 使用nginx或Apache负载PHP，PHP使用fastcgi方式运行，效率较高。 3、nginx + Apache + PHP + [...]]]></description>
			<content:encoded><![CDATA[<p>LAMP（Linux-Apache-MySQL-PHP）网站架构是目前国际流行的Web框架，该框架包括：Linux操作系统，Apache网络服务器，MySQL数据库，Perl、PHP或者Python编程语言，所有组成产品均是开源软件，是国际上成熟的架构框架，很多流行的商业应用都是采取这个架构，和Java/J2EE架构相比，LAMP具有Web资源丰富、轻量、快速开发等特点，微软的.NET架构相比，LAMP具有通用、跨平台、高性能、低价格的优势，因此LAMP无论是性能、质量还是价格都是企业搭建网站的首选平台。</p>
<p>对于大流量、大并发量的网站系统架构来说，除了硬件上使用高性能的服务器、负载均衡、CDN等之外，在软件架构上需要重点关注下面几个环节：使用高性能的操作系统（OS）、高性能的网页服务器（Web Server）、高性能的数据库（Databse）、高效率的编程语言等。下面我将从这几点对其一一讨论。</p>
<p>操作系统</p>
<p>Linux操作系统有很多个不同的发行版，如Red Hat Enterprise Linux、SUSE Linux Enterprice、Debian、Ubuntu、CentOS等，每一个发行版都有自己的特色，比如RHEL的稳定，Ubuntu的易用，基于稳定性和性能的考虑，操作系统选择CentOS（Community ENTerprise Operating System）是一个理想的方案。</p>
<p>CentOS（Community ENTerprise Operating System）是Linux发行版之一，是RHEL/Red Hat Enterprise Linux的精简免费版，和RHEL为同样的源代码，不过，RHEL和SUSE LE等企业版，提供的升级服务均是收费升级，无法免费在线升级，因此要求免费的高度稳定性的服务器可以用CentOS替代Red Hat Enterprise Linux使用。</p>
<p>&nbsp;</p>
<p><a href="http://www.phpdo.net/wp-content/uploads/2011/04/1908_1.jpg"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border: 0px;" title="1908_1" src="http://www.phpdo.net/wp-content/uploads/2011/04/1908_1_thumb.jpg" alt="1908_1" width="244" height="218" border="0" /></a></p>
<p>&nbsp;</p>
<p>Web服务器、缓存和PHP加速</p>
<p>Apache是LAMP架构最核心的Web Server，开源、稳定、模块丰富是Apache的优势。但Apache的缺点是有些臃肿，内存和CPU开销大，性能上有损耗，不如一些轻量级的Web服务器（例如nginx）高效，轻量级的Web服务器对于静态文件的响应能力来说远高于Apache服务器。</p>
<p>Apache做为Web Server是负载PHP的最佳选择，如果流量很大的话，可以采用nginx来负载非PHP的Web请求。nginx是一个高性能的HTTP和反向代理服务器，Nginx以它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。Nginx不支持PHP和CGI等动态语言，但支持负载均衡和容错，可和Apache配合使用，是轻量级的HTTP服务器的首选。</p>
<p>Web服务器的缓存也有多种方案，Apache提供了自己的缓存模块，也可以使用外加的Squid模块进行缓存，这两种方式均可以有效的提高Apache的访问响应能力。Squid Cache是一个Web缓存服务器，支持高效的缓存，可以作为网页服务器的前置cache服务器缓存相关请求来提高Web服务器的速度，把Squid放在Apache的前端来缓存Web服务器生成的动态内容，而Web应用程序只需要适当地设置页面实效时间即可。如访问量巨大则可考虑使用memcache作为分布式缓存。</p>
<p>PHP的加速使用eAccelerator加速器，eAccelerator是一个自由开放源码PHP加速器，优化和动态内容缓存，提高了性能PHP脚本的缓存性能，使得PHP脚本在编译的状态下，对服务器的开销几乎完全消除。它还有对脚本起优化作用，以加快其执行效率。使PHP程序代码执效率能提高1-10倍。</p>
<p>具体的解决方案有以下几种：</p>
<p>1、squid + Apache + PHP + eAccelerator</p>
<p>使用Apache负载PHP，使用squid进行缓存，html或图片的请求可以直接由squid返回给用户。很多大型网站都采用这种架构。</p>
<p>2、nginx/Apache + PHP（fastcgi） + eAccelerator</p>
<p>使用nginx或Apache负载PHP，PHP使用fastcgi方式运行，效率较高。</p>
<p>3、nginx + Apache + PHP + eAccelerator</p>
<p>此方案综合了nginx和Apache的优点，使用Apache负载PHP，nginx负责解析其他Web请求，使用nginx的rewrite模块，Apache端口不对外开放。</p>
<p>数据库</p>
<p>开源的数据库中，MySQL在性能、稳定性和功能上是首选，可以达到百万级别的数据存储，网站初期可以将MySQL和Web服务器放在一起，但是当访问量达到一定规模后，应该将MySQL数据库从Web Server上独立出来，在单独的服务器上运行，同时保持Web Server和MySQL服务器的稳定连接。</p>
<p>当数据库访问量达到更大的级别，可以考虑使用MySQL Cluster等数据库集群或者库表散列等解决方案。</p>
<p>总的来说，LAMP架构的网站性能会远远优于Windows IIS + ASP + Access（例如月光博客）这样的网站，可以负载的访问量也非常大，国内的大量个人网站如果想要支撑大访问量，采用LAMP架构是一个不错的方案。</p>
<p>综上所述，基于LAMP架构设计具有成本低廉、部署灵活、快速开发、安全稳定等特点，是Web网络应用和环境的优秀组合。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpdo.net/index.php/lamp-web.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP trim()函数</title>
		<link>http://www.phpdo.net/index.php/php-trim.html</link>
		<comments>http://www.phpdo.net/index.php/php-trim.html#comments</comments>
		<pubDate>Wed, 07 Dec 2011 12:04:36 +0000</pubDate>
		<dc:creator>老张</dc:creator>
				<category><![CDATA[php manuel]]></category>
		<category><![CDATA[PHP trim()函数]]></category>

		<guid isPermaLink="false">http://www.phpdo.net/?p=1781</guid>
		<description><![CDATA[PHP的trim()函数的作用是从字符串的两端删除空白字符和其他预定义字符。]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.phpdo.net/" target="_blank">PHP</a>的<strong><a title="trim" href="http://www.phpdo.net/index.php/php-trim.html" target="_blank">trim()函数</a></strong>的作用是从字符串的两端删除空白字符和其他预定义字符。</p>
<p>语法</p>
<p>trim(string,charlist)</p>
<table width="470" border="0" cellspacing="0" cellpadding="2">
<tbody>
<tr>
<td valign="top" width="200">参数</td>
<td valign="top" width="268">描述</td>
</tr>
<tr>
<td valign="top" width="200">string 必需。</td>
<td valign="top" width="268">规定要检查的字符串。</td>
</tr>
<tr>
<td valign="top" width="200">charlist 可选。&nbsp;</td>
<td valign="top" width="268">规定要转换的字符串。如果省略该参数，则删除以下所有字符：</p>
<p>“\0&#8243; – NULL<br />
“\t” – tab<br />
“\n” &#8211; new line<br />
“\x0B” &#8211; 纵向列表符<br />
“\r” &#8211; 回车<br />
” ” &#8211; 普通空白字符</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpdo.net/index.php/php-trim.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

