??xml version="1.0" encoding="utf-8" standalone="yes"?>
原型Qbool array_key_exists ( mixed key, array search )
描述Q给定的key存在于数l中时返回TRUEQ即使key对应的键gؓNULL也返回true。array_key_exists() 也可用于对象
2. empty
原型Qbool empty ( mixed var )
描述Q如?var 是非I或非零的|?empty() q回 FALSE。换句话_""??0"、NULL、FALSE、array()、var $var; 以及没有M属性的对象都将被认为是I的Q如?var 为空Q则q回 TRUE?
注意Q?br />A. empty是语句而不是函敎ͼ
B. empty只能用于变量Q诸如empty(addslashes($var))的用法是错误的,因ؓaddslashes($var)q回帔R?br />
3. isset
原型Qbool isset ( mixed var [, mixed var [, ...]] )
描述Q如果var存在则返回TRUEQ否则返回FALSEQ若使用 isset()试一个被讄?NULL 的变量,返?FALSE?/span>
?/span>意:
A. isset?/span>语句而不?/span>函数Q?br />B. isset?/span>能用于变量,若想常量是否设|可以用defined()函数?br />C. 使用unset实际上就是将var|ؓNULL?br />
性能比较Q?br />l论Qisset ~ empty > array_key_exists
原因Qisset和empty是语句,而array_key_exists是函敎ͼ后者比前者多了函数调用,因此性能上要E差。而isset和empty的范围是不一LQ主要区别在于gؓNULL的情况,需要特别注意?br />
]]>
前提QPHP没有q行在安全模?br />如果PHPq行在安全模式下Q那么在执行外部命o、打开文g、连接数据库、基于HTTP的认证这4个方面将会受到制U,可能在调用外部程序时无法获取预期的结果,此时需要设|特定目录,可以在php.ini中编辑safe_mode_exec_dir参数来指定?br />
1. exec
原型Qstring exec ( string command [, array &output [, int &return_var]] )
描述Q返回g存最后的输出l果Q而所有输出结果将会保存到$output数组Q?return_var用来保存命o执行的状态码Q用来检成功或p|Q?br />例子Q?ret = exec("ls -al", $output, $var);
注意Q?br />A. 输出l果会逐行q加?output中,因此在调用exec之前需要unset($output)Q特别是循环调用的时候?br />B. 如果想通过exec调用外部E序后马上l执行后l代码,仅仅在命令里?&"是不够的Q此时exec依然会等待命令执行完毕;需要再标准输出做重定向才可以Q例如:exec("ls -al >/dev/null &", $output, $var);
C. 要学会善用EscapeShellCmd()和EscapeShellArg()。函数EscapeShellCmd把一个字W串 中所有可能瞒qShell而去执行另外一个命令的字符转义。这些字W在Shell中是有特D含义的Q象分号Q|Q,重定向(>Q和从文件读?Q?lt;Q等。函数EscapeShellArg是用来处理命令的参数的。它在给定的字符串两边加上单引号Qƈ把字W串中的单引可{义,q样q个字符?可以安全地作ؓ命o的参数?br />
2. system
原型Qstring system ( string command [, int &return_var] )
描述Q执行给定的命oQ返回最后的输出l果Q第二个参数是可选的Q用来得到命令执行后的状态码?br />例子Q?ret = system("ls -al", $var);
注意Q略?br />
3. passthru
原型Qvoid passthru (string command [, int return_var])
描述Q执行给定的命oQ但不返回Q何输出结果,而是直接输出到显C备上Q第二个参数可选,用来得到命o执行后的状态码?br />例子Qpassthru("ls -al", $var);
注意Q略?br />
4. popen
原型Qresource popen ( string command, string mode )
描述Q打开一个指向进E的道Q该q程由派生给定的 command 命o执行而生?q回一个和 fopen() 所q回的相同的文g指针Q只不过它是单向的(只能用于L写)q且必须?pclose() 来关闭。此指针可以用于 fgets()Qfgetss() ?fwrite()?
例子Q?fd = popen("command", 'r'); $ret = fgets($fd);
注意Q只能打开单向道Q不?r'是'w'Qƈ且需要用pclose()来关闭?br />
5. proc_open
原型Qresource proc_open ( string cmd, array descriptorspec, array &pipes [, string cwd [, array env [, array other_options]]] )
描述Q与popencMQ但是可以提供双向管道。具体的参数读者可以自q阅资料,比如该博客:http://hi.baidu.com/alex_wang58/blog/item/a28657de16fec55195ee372a.html?br />注意Q?br />A. 后面需要用proc_close()关闭资源Qƈ且如果是pipecdQ需要用pclose()关闭句柄?br />B. proc_open打开的程序作为php的子q程Qphp退出后该子q程也会退出?br />C. W者在使用的时候遇到获取外部程序输出阻塞的问题Q也是在例子中的fgets($pipes[1])语句d了,无法l箋q行。经q多Ҏ证后发现Q问题一般出在外部程序中Q比如外部程序是CE序Q用fprintf(stdin, "**** \n");输出l果Q此旉要加上fflush(stdout);才行Q否则输出结果可能会暂留~存中,无法真正输出Q而php也就无法获取输出了?/span>
例子Q?
///< 打开道
$pwd = "*****";
$pipes = array();
$command = "*****";
$desc = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w'));
$handle = proc_open($command, $desc, $pipes, $pwd);
if (!is_resource($handle)) {
fprintf(STDERR, "proc_open failed.\n");
exit(1);
}
///< d
fwrite($pipes[0], "*****\n");
$ret = rtrim(fgets($pipes[1]), "\n");
///< 关闭道
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($handle);
]]>
一. 变量
1. php变量
A. 普通变量:{$var}
B. 兌数组Q{$array.var1.var2}
C. 数字数组Q{$array[0][1]}
D. 对象Q{$object->var}
E. 在引号内的用方法,以关联数lؓ例,其他cMQ{function var="{$array.var1.var2}"}
2. conf变量
A. {#var#}
B. 在引号内的用方法:{function var="{#var#}"}
3. smarty保留变量Q略?br />
? 变量调节?/strong>
1. capitalize / lower / upper
用途:首字母大?/ 转ؓ写 / 转ؓ大写
用法Q{$var|capitalize} / {$var|lower} / {$var|upper}
2. count_characters / count_paragraphs / count_sentences / count_words
用途:计算字节敎ͼ默认不计空格符 / 计算D落数量 / 计算句子数量 / 计算词数
用法Q{$var|count_characters} {$var|count_characters:true} / {$article|count_paragraphs} / {$article|count_sentences} / {$sentence|count_words}
3. cat
用途:字符串连?br /> 用法Q{$var|cat:" is a boy."}
4. nl2br
用途:换行W替换ؓ<br/>
用法Q{$var|nl2br}
5. regex_replace / replace
用途:正则替换 / 普通替?br /> 用法Q{$var|regex_replace:"/\[old\]/":"[new]"} / {$var|replace:"old":"new"}
6. spacify
用途:在每个字W间插入指定字符
用法Q{$var|spacify:"^_^"}
7. date_format
用途:格式化日期,cM"-1 days ago"?201111010000"、时间戳{都可以Q与strftime()功能cM
用法Q{$time|date_format:"%H:%M:%S"}
8. default
用途:当变量ؓI时Q设|默认?br /> 用法Q{$var|default:"no value"}
9. escape
用途:转码Q包括:html,htmlall,url,quotes,hex,hexentity,javascript
用法Q{$articleTitle|escape:"html"}
10.indent
用途:文字~进Q可以制定羃q字W数和用什么字W代?br /> 用法Q{$var|indent} {$var|indent:4} {$var|indent:4:"\t"}
11.string_format
用途:cM用sprintf
用法Q{$var|string_format:"%.2f"}
12.strip / strip_tags
用途:去除多余I白W,可以指定去除的字W?/ 去除<>以及包含在里面的所有字W?br /> 用法Q{$var|strip} {$var|strip:" "} / {$var|strip_tags}
13.truncate
用途:字符串截取,默认截取80字符Q可以指定追加的字符?br /> 用法Q{$var|truncate:40} {$var|truncate:40:"...":true}
14.l合修改?br /> 用途:思义Q可以将多个变量调节器组合用,中间用|来代?br /> 例子Q{$articleTitle|lower|spacify|truncate:30:"..."}
? 内徏函数
1. capture
用途:捕获模板内容到某变量varQƈ不进行输?br /> 用法Q?br /> 在{capture}{/capture}中间的数据被捕获Q可以?smarty.capture.var来用,不指定name的话Q默认ؓdefault
{capture name=banner}
This is a test.
{/capture}
2. foreach
用途:循环处理
用法Q?br /> from: 数组Q需要用$
item: 单元元素名称Q不需要用$
key: key名称Q不需要用$
name: 该@环的名称Q可以用于访问该循环Q例如:{$smarty.foreach.foreachname.varname}
{foreach item=contact from=$contacts}
{foreach key=key item=item from=$contact}
{$key}: {$item}<br>
{/foreach}
{/foreach}
注意Q在foreach中有一些特D的变量Q需要用{$smarty.foreach.foreachname.***}来访问:
iteration: 表示当前循环的执行次敎ͼ初始?
first: 循环W一ơ执行时被置为true
last: 同上
total: 用于昄循环执行的次敎ͼ在@环中或者@环后皆可使用
show: 是foreach的一个标{,用于军_是否昄该foreach的内?br />3. include / insert
用途:包含其他模板 / 与include不同Q?insert 所包含的内容不会被~存Q每ơ调用该模板都会重新执行该函?
用法Q{include file="footer.tpl" title="Main menu" logo="4. if elseif else
用途:分之判断
用法Q?br /> {if $name eq "Fred"}
Welcome Sir.
{elseif $name eq "Wilma"}
Welcome Ma'am.
{else}
Welcome, whatever you are.
{/if}
5. ldelim / rdelim
用途:分别表示左括受右括号Q因两个W号被用作smarty模板的标识符
用法Q?br /> {ldelim} {rdelim}
6. literal
用途:在内部的数据当做文本处理Q不使用smarty模板解析Q主要用于javascript脚本{?br /> 用法Q?br /> {literal}
......
{/literal}
7. section
用途:循环处理
用法Q?br /> name: 该@环的名称
loopQ决定@环次数的数组Q注意这里的使用Ҏ比较特别Q可以用section来对多个数组q行处理Q但必须先用可以军_循环ơ数的数l给loop赋?br /> {section name=customer loop=$custid}
id: {$custid[customer]}<br>
name: {$name[customer]}<br>
address: {$address[customer]}<br>
{section name=contact loop=$contact_type[customer]}
{$contact_type[customer][contact]}: {$contact_info[customer][contact]}<br>
{/section}
<p>
{/section}
如果要遍历多l关联数l,需要这h使用Q?br /> {section name=customer loop=$contacts}
name: {$contacts[customer].name}<br>
home: {$contacts[customer].home}<br>
cell: {$contacts[customer].cell}<br>
e-mail: {$contacts[customer].email}<p>
{/section}
注意Q与foreachcMQ在section中同h一些特D变量可供用,使用Ҏ是:{$smarty.section.sectionname.***}
index: 昄当前循环的烦引,默认?或者start开?br /> index_prev: 昄上一个@环烦引|默认?1开?br /> index_next: 同上Q直x后都比上一ơ大1
ineration: 同foreachQ与index不同Q后者是索引
first: 同foreach
last: 同foreach
show: 同foreach
total: 同foreach
8. strip
用途:位于{strip}{/strip}内部html标签外的所有空格和回R清除q净Qƈ以html标签开头和l尾
用法Q?br /> {strip}
<table border=0>
<tr>
<td>
<A HREF="{$url}">
<font color="red">This is a test</font>
</A>
</td>
</tr>
</table>
{/strip}
上述输出为:
<table border=0><tr><td><A HREF=" color="red">This is a test</font></A></td></tr></table>
? E序员需要注意的地方
1. 帔R
SMARTY_DIRQSMARTY_DIR帔R用于定位smartycL件的完整pȝ路径Q必M斜杠l束Q也可以不定义,smarty模板会自动创建合适的倹{?br />2. cd?br /> $template_dir: 模板目录Q也是各html文g攄目录Q默认ؓ"./templates"
$compile_dir: ~译后的模板目录Q经qsmarty解析后的html文g攄目录Q默认ؓ"./templates_c"
$config_dir: 模板配置文g目录Q默认ؓ"./configs"
$plugins_dir: 插g目录Q默认ؓSMARTY_DIR ?"plugins"
$cache_dir: 存放模板~存的目录,默认?./cache"
$debugging: 可以启动调试控制収ͼ默认为falseQ很有用啊!Q!
$debug_tpl: 定义用于调试控制台的模板文g名字Q默认ؓSMARTY_DIR . "libs/debug.tpl"
$global_assign: 用于定义全局变量Q例如:
php里:$this->tpl->global_assign = array('my_global_1' => .....);
在template里:{$smarty.my_global_1.***}
$compile_check: 自动~译模板Q默认设|ؓtrueQ投入品后为性能赯Q可以设|ؓfalse?br /> $force_compile: 每次调用旉新编译模板,默认为falseQ不?compile_check的限Ӟ一旦设|ؓtrue后会重新~译?br /> $caching: 是否~存模板输出Q默认ؓfalseQ有利于增强性能?br /> $caching_lifetime: ~存生存旉Q只?caching为true时有效,-1表示永远有效Q?表示永远需要重新生成。单位是U?br /> 注意Q?compile_check?force_compile?caching三者的关系如下Q?br /> A. 如果讄?compile_checkQ如果Q何模板文件或配置文g更新Q都会重新编译,~存也会重新生成Q?br /> B. 如果讄?force_compileQ则$compile_check不v作用Q而缓存也M重新生成Q?br /> C. 如果没有讄$cachingQ则没有~存Q性能受一定媄响?br />
? smarty的method
1. assign: Ҏ板用到的php变量q行赋?br />2. assign_by_ref: 也是赋|不过是引用赋?br />3. clear_all_assign: 清除所有赋?br />4. clear_all_cache: 清除所有缓存,参数可以指定阈值时?br />5. clear_assign: 清除某个赋|可以指定单个变量名或者数l?br />6. clear_cache: 清除某个template的缓存,需要指定template的名U?br />7. clear_config: 清除所有配|变量,如果指定则清除特定配|变?br />8. config_load: 加蝲某配|文件ƈ数据输出到模板
9. display: 昄某个模板
10.fetch: 捕获某个模板的输出,与display不同的是Q模板输出内容ƈ不会直接昄出来Q有什么用呢?Q?Q?br />11.get_config_vars: 获取所有配|变量的|也可以指定某个具体的变量?br />12.get_template_vars: 获取所有模板变量的|也可以指定某个具体的变量?br />13.is_cached: 判断某模板的~存是否存在Q只有在$caching讄为true时才有效
14.template_exists: 判断某模板是否存?br />
该例中,A::y()调用了A::x()Q而B::x()覆盖了A::x()Q那么当调用B::y()ӞB::y()应该调用A::x()q是 B::x()呢?在C++中,如果A::x()未被定义函数Q那么B::y()Q也是A::y()Q将调用A::x()Q而如果A::x()使用 virtual关键字定义成虚函敎ͼ那么B::y()调用B::x()?br />然而,在PHP5中,虚函数的功能是由 self ?$this 关键字实现的。如果父cMA::y()中?self::x() 的方式调用了 A::x()Q那么在子类中不论A::x()是否被覆盖,A::y()调用的都是A::x()Q而如果父cMA::y()使用 $this->x() 的方式调用了 A::x()Q那么如果在子类中A::x()被B::x()覆盖QA::y()会调用B::x()?/p>
上例的运行结果如下:
A::x() was called. A::y() was called.
--
B::x() was called. A::z() was called.
$test = new Test();
$b = var_export($test, true);
var_dump($b);
class Test {
public $a;
public static function __set_state($array) {
$ab = new Test();
$ab->a = 10;
return $ab;
}
}
1.数组函数
array_product() array_search() array_unique() extract() array_count_values() array_key_exists() array_sum() 2.文g函数 basename() dirname() feof() fflush() file() file_exists() file_get_contents() file_put_contents filesize() filetype() flock() is_dir() is_executable() parse_ini_file() tempnam() tmpfile() touch() 3.字符串函?/strong> addslashes() chr() convert_uuencode() convert_uudecode() crc32() crypt() explode() htmlentities() htmlspecialchars_decode() htmlspecialchars() implode() md5() md5_file() nl2br() number_format() ord() parse_str() str_ireplace() str_shuffle() str_split() str_word_count() strcasecmp() strchr() strcmp() strip_tags() stripslashes() stripos() strpos() strrev() strtolower() strtoupper() substr() substr_replace() ucwords() parse_url(); 解析URLQ返回数l,[HOST]="ABC.COM";[PATH]="INDEX.PHP" 4.字符串加?/strong> md5 urlencode urldecode base64_encode base64_decode convert_uuencode() convert_uudecode() 5.正则表达?/strong> [^a-z] str_replace(); ereg_replace(); preg_match(); preg_match_all(); preg_replace(); preg_split(); 6.数据验证 is_numeric(); is_bool(); is_string(); intval(); strval(); settype($input,integer); 讄cd 7.~冲区控制函?/strong> flush — h输出~冲?br />保存在输出缓冲区的内容会被发送到览?br />ob_start — 打开输出~冲?br />q样所有的输出信息不在直接发送到览器,而是保存在输出缓冲区里面
ob_get_contents — q回输出~冲区的内容
如果你想以后处理输出的内容,可以调用q个函数保留一个备?br />ob_get_length — q回输出~冲区的内容长度
ob_end_flush — l束Q发送)输出~冲区的内容Q关闭输出缓冲区
ob_end_clean — 删除Q放弃)输出~冲区的内容Q关闭输出缓冲区
如果你的E序发现输出内容有问题,可以攑ּ所有输出内容,可以防止泄漏某些U密信息
ob_implicit_flush — 打开或关闭直接刷?br />打开后,每个脚本输出都直接发送到览器,不再需要调?flush(),
]]>
1、如果能类的方法定义成staticQ就量定义成staticQ它的速度会提升将q?倍?br />PSQ事实上Qfunction、method、static method的速度不会有太大差异。具体可?#8220;PHP函数的实现原理及性能分析【{载?/span>”一文?/span>
2?row[’id’] 的速度?row[id]?倍?br />PSQ不太懂Q貌似差异只有后者会先判断idq个宏是否存在,如果不存在则自动转变为字W串?/span>
3、echo ?print 快,q且使用echo的多重参?译注Q指用逗号而不是句?代替字符串连接,比如echo $str1,$str2?/p>
4、在执行for循环之前定最大@环数Q不要每循环一ơ都计算最大|最好运用foreach代替?br />PSQ像count、strlenq样的操作其实是O(1)的,因此不会带来太多消耗,当然避免每次循环都计是比较好的{略。最好用foreach代替forQ这个效率更高,如果考虑到foreach($array as $var)每次拯的消耗,可以使用foreach($array as &$var)q样的引用?/span>
5、注销那些不用的变量尤其是大数l,以便释放内存?br />PSQ如果没有记错的话,unset($array)不会立刻释放内存Q但随时释放是个好习惯?/span>
6、尽量避免用__getQ__setQ__autoload?/p>
7、require_once()代h昂贵?br />PSQrequire_once和include_once需要判重,因此效率上要低,但是5.2版本后效率问题已l基本解冟?/span>
8、include文g时尽量用绝对\径,因ؓ它避免了PHP去include_path里查找文件的速度Q解析操作系l\径所需的时间会更少?br />PSQ支持,量用iniset()来设|include_path?/span>
9、如果你想知道脚本开始执?译注Q即服务器端收到客户端请?的时刻,使用$_SERVER['REQUEST_TIME']要好于time()?br />PSQ?_SERVER['REQUEST_TIME']保存了发赯h时刻的时间戳Q而time()则返回当前时ȝUnix旉戟?/span>
10、函C替正则表辑ּ完成相同功能?br />PSQ这U函数是指strtok、strstr、strpos、str_replace、substr、explode、implode{等?/span>
11、str_replace函数比preg_replace函数快,但strtr函数的效率是str_replace函数的四倍?br />PSQ字W串操作比正则替换要快?/span>
12、如果一个字W串替换函数Q可接受数组或字W作为参敎ͼq且参数长度不太长,那么可以考虑额外写一D|换代码,使得每次传递参数是一个字W,而不是只写一行代码接受数l作为查询和替换的参数?br />PSQ需要考虑到内|函数和用户自定义函数的开销差异Q恐怕这U做法得不偿失?/span>
13、用选择分支语句(译注Q即switch case)好于使用多个ifQelse if语句?br />PSQphp中switch支持数值和字符串变量,比C的switch要好用,使用?/span>
14、用@屏蔽错误消息的做法非怽效,极其低效?br />PSQ有什么替代方法吗Q没有的话还是不得不用的……
15、打开apache的mod_deflate模块Q可以提高网늚览速度?/p>
16、数据库q接当用完毕时应关掉,不要用长q接?br />PSQ在q接之前Q最好设|一下相应的时机制Q例如链接超时、读写超时、等待超时等?/span>
17、错误消息代hc?/p>
18、在Ҏ中递增局部变量,速度是最快的。几乎与在函C调用局部变量的速度相当?/p>
19、递增一个全局变量要比递增一个局部变量慢2倍?/p>
20、递增一个对象属?如:$this->prop++)要比递增一个局部变量慢3倍?/p>
21、递增一个未预定义的局部变量要比递增一个预定义的局部变量慢9?0倍?/p>
22、仅定义一个局部变量而没在函C调用它,同样会减慢速度(其程度相当于递增一个局部变?。PHP大概会检查看是否存在全局变量?/p>
23、方法调用看来与cM定义的方法的数量无关Q因为我(在测试方法之前和之后?d?0个方法,但性能上没有变化?/p>
24、派生类中的Ҏq行h要快于在基类中定义的同样的方法?/p>
25、调用带有一个参数的I函敎ͼ其花费的旉相当于执??ơ的局部变量递增操作。类似的Ҏ调用所p的时间接q于15ơ的局部变量递增操作?/p>
26、Apache解析一个PHP脚本的时间要比解析一个静态HTML面??0倍。尽量多用静态HTML面Q少用脚本?/p>
27、除非脚本可以缓存,否则每次调用旉会重新编译一ơ。引入一套PHP~存机制通常可以提升25%?00%的性能Q以免除~译开销?/p>
28、尽量做~存Q可使用memcached。memcached是一N性能的内存对象缓存系l,可用来加速动态Web应用E序Q减L据库负蝲。对q算?(OP code)的缓存很有用Q得脚本不必ؓ每个h做重新编译?/p>
29、当操作字符串ƈ需要检验其长度是否满某种要求Ӟ你想当然C使用strlen()函数。此函数执行h相当快,因ؓ它不做Q何计,只返回在zval l构(C的内|数据结构,用于存储PHP变量)中存储的已知字符串长度。但是,׃strlen()是函敎ͼ多多少会有些慢Q因为函数调用会l过诸多步骤Q如字母写?译注Q指函数名小写化QPHP不区分函数名大小?、哈希查找,会跟随被调用的函Ch行。在某些情况下,你可以用isset() 技巧加速执行你的代码?/p>
(举例如下)
if (strlen($foo) < 5) { echo “Foo is too short”$$ }
(与下面的技巧做比较)
if (!isset($foo{5})) { echo “Foo is too short”$$ }
调用isset()恰y比strlen()快,因ؓ与后者不同的是,isset()作ؓ一U语al构Q意味着它的执行不需要函数查扑֒字母写化。也是_实际上在验字W串长度的顶层代码中你没有花太多开销?br />PSQ长见识了?/span>
30、当执行变量$i的递增或递减Ӟ$i++会比++$i慢一些。这U差异是PHPҎ的,q不适用于其他语aQ所以请不要修改你的C或Java代码q指望它们能立即变快Q没用的?+$i更快是因为它只需?条指?opcodes)Q?i++则需?条指令。后|递增实际上会产生一个时变量,q个临时变量随后被递增。而前|递增直接在原g递增。这是最优化处理的一U,正如Zend的PHP优化器所作的那样。牢记这个优化处理不׃ؓ一个好LQ因为ƈ不是所有的指o优化器都会做同样的优化处理,q且存在大量没有装配指o优化器的互联|服务提供商(ISPs)和服务器?/p>
31、ƈ不是事必面向对象(OOP)Q面向对象往往开销很大Q每个方法和对象调用都会消耗很多内存?/p>
32、ƈ非要用类实现所有的数据l构Q数l也很有用?/p>
33、不要把Ҏl分得过多,仔细x你真正打重用的是哪些代?
34、当你需要时Q你总能把代码分解成Ҏ?br />PSQ分解成Ҏ要适当Q行数少使用频率高的Ҏ量用直接写代码Q可以减函数堆栈开销Q且Ҏ嵌套不宜q深Q否则大大媄响PHP的运行效率?/span>
35、尽量采用大量的PHP内置函数?/p>
36、如果在代码中存在大量耗时的函敎ͼ你可以考虑用C扩展的方式实现它们?/p>
37、评估检?profile)你的代码。检验器会告诉你Q代码的哪些部分消耗了多少旉。Xdebug调试器包含了验程序,评估验M上可以显C出代码的瓶颈?/p>
38、mod_zip可作为Apache模块Q用来即时压~你的数据,q可让数据传输量降低80%?/p>
39、在可以用file_get_contents替代file、fopen、feof、fgets{系列方法的情况下,量用file_get_contentsQ因Z的效率高得多!但是要注意file_get_contents在打开一个URL文g时候的PHP版本问题;
PSQ这个要CQ尽量用file_get_contents和file_put_contentsQ不需要自己判断文件句柄打开是否成功?/span>
40、尽量的进行文件操作,虽然PHP的文件操作效率也不低?
41、优化Select SQL语句Q在可能的情况下量的q行Insert、Update操作(在update上,我被恶批q?;
42、尽可能的用PHP内部函数(但是我却Z找个PHP里面不存在的函数Q浪费了本可以写Z个自定义函数的时_l验问题?);
PSQ内|函数比用户自定义函数效率高了将q一个数量?/span>
43、@环内部不要声明变量,其是大变量Q对?q好像不只是PHP里面要注意的问题?);
PSQ这个必ȝQ变量过多或者过大时Q每ơ重分配的开销无法忽略?/span>
44、多l数l尽量不要@环嵌套赋?
45、在可以用PHP内部字符串操作函数的情况下,不要用正则表辑ּ;
46、foreach效率更高Q尽量用foreach代替while和for循环;
47、用单引h代双引号引用字符?
PSQ晕Q这个不是W一条吗Q?/span>
48?#8220;用i+=1代替i=i+1。符合c/c++的习惯,效率q高”;
49、对global变量Q应该用完就unset()?
<?php
//创徏对象
$mysqli = mysqli_init();//讄时选项
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5);//q接
$mysqli->real_connect('localhost', 'my_user', 'my_password', 'world');//如果时或者其他连接失败打印错误信?/span>
if (mysqli_connect_errno()) {
printf("Connect failed: %s/n", mysqli_connect_error());
exit();
}
//成功输出q接信息
printf ("Connection: %s/n.", $mysqli->host_info);$mysqli->close();
?>
q个是连接超Ӟ但是有些时候我们需要查询读写超Ӟ比如说我们一个数据库压力很大Q或者连接很多,那么数据库查询就很缓慢,但是我希望某些不重要的数据,比如说文章点Lq种如果查询时了就不显C,臛_能够保证M面正确昄Q但是查遍PHP手册没有发现q个操作选项或者函数。手册里只有q么四个选项Q?/p>
跟踪 mysqli 的扩展源代码发现它底层调用的?libmysqlclient ?mysql_optionsQ?/p>
php-5.2.8/ext/mysqli/mysqli_api.c
q且在mysqli的PHP扩展中就只导Z几个变量Q?/p>
php-5.2.8/ext/mysqli/mysqli.c
大概看了一?libmysqlclient 的代码,发现其实它自带是有读写超时设|的Q?/p>
mysql-5.1.30/sql-common/client.c
因ؓ它自己定义了很多操作选项Q只是php扩展里没有:
mysql-5.1.30/include/mysql.h
看看mysql中的d时是如何实现的Q?/span>
mysql-5.1.30/sql-common/client.c
d时真正操作的地方,时处理q里重试了两ơ,q是写死了:
mysql-5.1.30/sql/net_serv.cc
现在基本得出了结论:
按照上面查看代码来看Q目前PHP针对MySQL查询时以下限制Q?/span> 1. 时讄单位为秒Q最配|?U?/span> 2. 但mysql底层的read会重试两ơ,所以实际会?3 U?/span> 重试两次 + 自n一?= 3倍超时时间?/span> 那么是说最超时时间是3U,不会低于q个|对于大部分应用来说可以接受,但是对于部分应用需要优化?/span>
现在我们来看看如果我们自p讄时Q我们自己压?MYSQL_OPT_READ_TIMEOUT 也是可以辑ֈd时效果的,写一D代码来试一下:
<?php
//自己定义d时帔R
if (!defined('MYSQL_OPT_READ_TIMEOUT')) {
define('MYSQL_OPT_READ_TIMEOUT', 11);
}
if (!defined('MYSQL_OPT_WRITE_TIMEOUT')) {
define('MYSQL_OPT_WRITE_TIMEOUT', 12);
}//讄时
$mysqli = mysqli_init();
$mysqli->options(MYSQL_OPT_READ_TIMEOUT, 3);
$mysqli->options(MYSQL_OPT_WRITE_TIMEOUT, 1);//q接数据?br />$mysqli->real_connect("localhost", "root", "root", "test");
if (mysqli_connect_errno()) {
printf("Connect failed: %s/n", mysqli_connect_error());
exit();
}//执行查询 sleep 1U不时
printf("Host information: %s/n", $mysqli->host_info);
if (!($res=$mysqli->query('select sleep(1)'))) {
echo "query1 error: ". $mysqli->error ."/n";
} else {
echo "Query1: query success/n";
}//执行查询 sleep 9U会时
if (!($res=$mysqli->query('select sleep(9)'))) {
echo "query2 error: ". $mysqli->error ."/n";
} else {
echo "Query2: query success/n";
}$mysqli->close();
echo "close mysql connection/n";
?>
查看上面代码的执行结果,验证了上面的观点Q第一个查询成功了Q第二个查询q接被断开了:
基本上到q里基本能够解决PHP在针对MySQLd查询操作时的处理了Q希望对你有帮助?br />
// #####################################################
// #####################################################
本h按照作者的Ҏ~代码,q行时在$mysqli->options(MYSQL_OPT_READ_TIMEOUT, 3);q一步就q回false了,实际查询时READ_TIMEOUT也没有发挥作用。后来看php-5.3.8\php-5.3.8\ext\mysqli\mysqli_api.c源代码时发现PHP_FUNCTION(mysqli_options)里有一行代码:
expected_type = mysqli_options_get_option_zval_type(mysql_option);
q个函数的作用是判断options值类型,其中有一D:
#ifdef MYSQL_OPT_READ_TIMEOUT
case MYSQL_OPT_READ_TIMEOUT:
case MYSQL_OPT_WRITE_TIMEOUT:
case MYSQL_OPT_GUESS_CONNECTION:
case MYSQL_OPT_USE_EMBEDDED_CONNECTION:
case MYSQL_OPT_USE_REMOTE_CONNECTION:
case MYSQL_SECURE_AUTH:
#endif /* MySQL 4.1.1 */
.........
return IS_LONG;
.........
default:
return IS_NULL;
貌似׃没有定义MYSQL_OPT_READ_TIMEOUTq个宏,所以options{于MYSQL_OPT_READ_TIMEOUT时被归到IS_NULL的返回结果中了,此时PHP_FUNCTION(mysqli_options)会执行如下结果:
switch (expected_type) {
case IS_STRING:
ret = mysql_options(mysql->mysql, mysql_option, Z_STRVAL_PP(mysql_value));
break;
case IS_LONG:
l_value = Z_LVAL_PP(mysql_value);
ret = mysql_options(mysql->mysql, mysql_option, (char *)&l_value);
break;
default:
ret = 1;
break;
}
也就是说Q不会执行mysql_options()ҎQ而是直接q回false?/span>
在Q何语a中,函数都是最基本的组成单元。对于php的函敎ͼ它具有哪些特点?函数调用是怎么实现的?php函数的性能如何Q有什么用徏议?
本文从原理出发q行分析l合实际的性能试试对这些问题进行回{,在了解实现的同时更好的编写phpE序。同时也会对一些常见的php函数q行介绍?
一个php函数最l是如何执行Q这个流E是怎么L呢?
要回{这个问题,我们先来看看php代码的执行所l过的流E?
从图1可以看到Qphp实现了一个典型的动态语a执行q程Q拿CD代码后Q经q词法解析、语法解析等阶段后,
源程序会被翻译成一个个指o(opcodes)Q然后ZEND虚拟机顺ơ执行这些指令完成操作。Php本n是用c实现的,
因此最l调用的也都是c的函敎ͼ实际上,我们可以把php看做是一个c开发的软g?br />通过上面描述不难看出Qphp中函数的执行也是被翻译成了opcodes来调用,每次函数调用实际上是执行了一条或多条指o?
对于每一个函敎ͼzend都通过以下的数据结构来描述
typedef union _zend_function { zend_uchar type; /* MUST be the first element of this struct! */ struct { zend_uchar type; /* never used */ char *function_name; zend_class_entry *scope; zend_uint fn_flags; union _zend_function *prototype; zend_uint num_args; zend_uint required_num_args; zend_arg_info *arg_info; zend_bool pass_rest_by_reference; unsigned char return_reference; } common; zend_op_array op_array; zend_internal_function internal_function; } zend_function; typedef struct _zend_function_state { HashTable *function_symbol_table; zend_function *function; void *reserved[ZEND_MAX_RESERVED_RESOURCES]; } zend_function_state;
其中Q?br />type标明了函数的cdQ用户函数、内|函数、重载函数?br />Common中包含函数的基本信息Q包括函数名Q参C息,函数标志Q普通函数、静态方法、抽象方法){内宏V?br />另外Q对于用户函敎ͼq有一个函数符可Q记录了内部变量{,q个在后面详述?
Zendl护了一个全局function_tableQ这是一个大的hash表。函数调用的时候会首先Ҏ函数名从表中扑ֈ对应的zend_function?br />当进行函数调用时候,虚拟ZҎtype的不同决定调用方法, 不同cd的函敎ͼ其执行原理是不相同的 ?
内置函数Q其本质上就是真正的c函数Q每一个内|函敎ͼphp在最l编译后都会展开成ؓ一个名叫zif_xxxx的functionQ比如我们常见的sprintfQ?br />对应到底层就是zif_sprintf。Zend在执行的时候,如果发现是内|函敎ͼ则只是简单的做一个{发操作?
Zend提供了一pd的api供调用,包括参数获取、数l操作、内存分配等。内|函数的参数获取Q通过zend_parse_parametersҎ来实玎ͼ
对于数组、字W串{参敎ͼzend实现的是拷贝,因此q个效率是很高的。可以这栯Q对于php内置函数Q其效率和相应c函数几乎相同Q?br />唯一多了一ơ{发调用?
内置函数在php中都是通过so的方式进行动态加载,用户也可以根据需要自q写相应的soQ也是我们常说的扩展?br />ZEND提供了一pd的api供扩展用,下面是mysqli_real_query函数的C函数实现Q?br />php-5.3.8\php-5.3.8\ext\mysqli\mysqli_api.c
PHP_FUNCTION(mysqli_real_query)
{
MY_MYSQL *mysql;
zval *mysql_link;
char *query = NULL;
int query_len;
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) {
return;
}
MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
MYSQLI_DISABLE_MQ; /* disable multi statements/queries */
if (mysql_real_query(mysql->mysql, query, query_len)) {
MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
RETURN_FALSE;
}
if (!mysql_field_count(mysql->mysql)) {
if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
php_mysqli_report_index(query, mysqli_server_status(mysql->mysql) TSRMLS_CC);
}
}
RETURN_TRUE;
}
和内|函数相比,用户通过php实现的自定义函数h完全不同的执行过E和实现原理。如前文所qͼ
我们知道php代码是被译成ؓ了一条条opcode来执行的Q用户函C不例外,实际中每个函数对应到一lopcodeQ?br />q组指o被保存在zend_function中。于是,用户函数的调用最l就是对应到一lopcodes的执行?
对于栈的l护Qzend在这里做了优化。预先分配一个长度ؓN的静态数l来模拟堆栈Q?br />q种通过静态数l来模拟动态数据结构的手法在我们自qE序中也l常有用,q种方式避免了每ơ调用带来的内存分配、销毁?br />ZEND只是在函数调用结束时当前栈的W号表数据clean掉即可?br />因ؓ静态数l长度ؓNQ一旦函数调用层ơ超qNQ程序不会出现栈溢出Q这U情况下zend׃q行W号表的分配、销毁,因此会导致性能下降很多?br />在zend里面QN目前取值是32。因此,我们~写phpE序的时候,函数调用层次最好不要超q?2?br />当然Q如果是web应用Q本w可以函数调用层ơ的深度?
虽然函数名长度对性能有一定媄响,但具体有多大呢?q个问题应该q是需要结合实际情冉|考虑Q如果一个函数本w比较复杂的话,
那么Ҏ体的性能影响q不大?br />一个徏议是对于那些会调用很多次Q本w功能又比较单的函数Q可以适当取一些言意赅的名字?
在php中,有这样一些函敎ͼ它们在用上是标准的函数用法Q但底层实现却和真正函数调用完全不同Q这些函C属于前文提到的三Ufunction中的M一c,
其实质是一条单独的opcodeQ这里估且叫做伪函数或者指令函数?
如上所_伪函C用v来和标准的函数ƈ无二_看v来具有相同的特征。但是他们最l执行的时候是被zend反映成了一条对应的指oQopcodeQ来调用Q?br />因此其实现更接近于if、for、算术运等操作?
通过上面的介l可以看出,伪函数由于被直接译成指令来执行Q和普通函数相比少了一ơ函数调用所带来的开销Q因此性能会更好一些?br />我们通过如下试来做一个对比?Array_key_exists和isset两者都可以判断数组中某个key是否存在Q看一下他们的性能
从图上可以看出,和array_key_exists相比Qisset性能要高出很多,基本是前者的4倍左叻I而即使是和空函数调用相比Q?br />其性能也要高出1倍左叟뀂由此也侧面印证再次说明了php函数调用的开销q是比较大的?