Submitted by gouki on 2009, April 28, 11:05 PM
风雪之隅的网站上大多是对PHP的底层进行关注的文章,如果对PHP的核心内容有兴趣不妨多翻阅一下他的网站。
本文的标题,其实是一个老问题了。
大家都知道,PHP对于没有引号的字符串,会当成常量来处理,如果该常量不存在,则直接输出该字符串。也就是多做了几步处理。
事实上,上面的这个知识点,很早就知道,但,不是我自己研究出来的。虽然自己写过代码进行测试过。
雪候鸟则直接从OPCODE上进行查看,给你一个直观印象。好,我们来看看原文吧
地址:http://www.laruence.com/2009/04/24/695.html
内容:
我看到过很多人操作数组的时候, 对于数组中的非数字键名不使用引号,
PHP代码
- $array[key] = $value;
我可以理解有些人可能会觉得这样的代码很”整洁”, 并且也能正常执行.
更甚至,如果他很”幸运的”php配置的好:
PHP代码
- error_reporting = ~E_NOTICE
他也许永远都沉浸在自己的”整洁”风格中, 看不到任何的NOTICE提示, 也不会意识到, 他这么做, 能损失多少的性能~
来, 我们一起来看看:
PHP代码
- good.php:
- <?php
- $array = array();
- $i = 0;
- while(++$i < 1000){
- $array['good'] = 2;
- }
- ?>
-
- bad.php:
- <?php
- $array = array();
- $i = 0;
- while(++$i < 1000){
- $array[good] = 2;
- }
- ?>
分别看运行时间(多次平均时间):
加引号的:
XML/HTML代码
- $ time php -f good.php
-
- real 0m0.013s
- user 0m0.005s
- sys 0m0.007s
不加引号的:
XML/HTML代码
- $ time php -f bad.php
-
- PHP Notice: Use of undefined constant bad - assumed 'bad' in /home/huixinchen/tmp/bad.php on line
- (此处省略999行NOTICE)
- real 0m0.100s
- user 0m0.020s
- sys 0m0.029s
看看,差别有多大?
哦, 或许我们应该模拟一下那些”幸运的”人们的情况, 去掉花费在记录NOTICE的开销, 看看~
XML/HTML代码
- $ time php -f bad.php
-
- real 0m0.037s
- user 0m0.018s
- sys 0m0.018s
我们可以看出, 基本上, 使用引号,和不使用引号的效率损失在3倍以上
那么, 这些效率损失到哪里去了呢?
我们分别看下, 俩个文件生成的OPCODE序列:
good.php :
C++代码
- filename: /home/huixinchen/tmp/good.php
- compiled vars: !0 = $array, !1 = $i
- line # op fetch ext return operands
- -------------------------------------------------------------------------------
- 2 0 INIT_ARRAY ~0
- 1 ASSIGN !0, ~0
- 3 2 ASSIGN !1, 0
- 4 3 PRE_INC $3 !1
- 4 IS_SMALLER ~4 $3, 1000
- 5 JMPZ ~4, ->9
- 5 6 ZEND_ASSIGN_DIM !0, 'good'
- 7 ZEND_OP_DATA 2, $6
- 6 8 JMP ->3
- 8 9 RETURN 1
- 10* ZEND_HANDLE_EXCEPTION
bad.php :
C++代码
- filename: /home/huixinchen/tmp/bad.php
- compiled vars: !0 = $array, !1 = $i
- line # op fetch ext return operands
- -------------------------------------------------------------------------------
- 2 0 INIT_ARRAY ~0
- 1 ASSIGN !0, ~0
- 3 2 ASSIGN !1, 0
- 4 3 PRE_INC $3 !1
- 4 IS_SMALLER ~4 $3, 1000
- 5 JMPZ ~4, ->10
- 5 6 FETCH_CONSTANT ~5 'bad'
- 7 ZEND_ASSIGN_DIM !0, ~5
- 8 ZEND_OP_DATA 2, $7
- 6 9 JMP ->3
- 8 10 RETURN
我们可以看出(其实,根据NOTICE的提示也知道), PHP会把没有引号引起来的键名当作是常量去获取, 当找不到的时候, 抛出一个NOTICE, 然后再根据”常量明”生成一个字符串, 然后再讲这个字符串做为键名继续~
聪明的你一定会想到, 可能会出现如下不可预期的错误:
PHP代码
- define('key_name' , 'laruence');
- ....
-
- $array[key_name] = 2;
-
明白了么? 数组中的非数字键的键名一定要有引号啊~
哦, 还记得有人会说, 那在字符串变量替换的时候, 写引号会导致错误,
恩, 标准写法:
PHP代码
- $string = "variable value is {$array['key']}"
我很赞同:”be lazy”, 但是, lazy也是应该有原则的.
最后, 好的代码,不应该通过关闭error_reporting来伪装.
附注, FETCH_CONSTANT OPCODE中找不到常量的相关逻辑:
C++代码
- ....
- if (!zend_get_constant(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
- zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
- opline->op2.u.constant.value.str.val,
- opline->op2.u.constant.value.str.val);
- EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
- zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
- }
- ....
——EOF——
膘叔最受不了的,就是discuz,特别是模版中的变量,全部是不含单引号的。写起来是方便啊。但是性能不敢恭维。所以common.inc.php的前面几句就是error_reporting了。。隐藏掉,看你怎么办,有本事你咬我呀。。
我还能怎么办?
Tags: 风雪之隅, 细节
PHP | 评论:1
| 阅读:21855
Submitted by gouki on 2009, April 22, 9:36 AM
HTML重构,以前是一个新鲜的东西,我也没有理解,博客园上有人在介绍,还写了三篇。。。
我这里只简单的复制点东西,还是以链接为重吧。(战略篇全文如下)
《Refactoring HTML: Improving the Design of Existing Web Applications》是一本精彩的HTML重构指南,作者给出了HTML重构的实践路线和方法。本文是《Refactoring HTML》的读书笔记,按照我的理解将全书的分为:战略篇,战术篇,工具篇。
本文是战略篇:全局方略的角度介绍重构的内涵,原因,时机,目标
嗯哼,我们开始:
进行重构就像打一场仗,而战争的发起是要慎重考虑的,《孙子兵法》里面讲“兵者,国之大事,死生之地,存亡之道,不可不察也。”所以动手重构之前首先要回答下面几个问题:
- 什么是重构?
- 为什么进行HTML重构?
- 什么时候进行HTML重构?
- HTML重构的目标是什么?
- 面对质疑:还要重构么?
什么是重构 Refactoring?
本书侧重实战,没有《UML Distilled》那样高屋建瓴的抽象,即使有抽象,抽象层面牵扯的细节过多(这一点在后续的阅读中也可以发现)。这一部分内容我援引了《Refactoring: Improving the Design of Existing Code》对重构的定义:
Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.
Refactor (verb): to restructure software by applying a series of refactorings without changing its observable behavior.
为什么进行HTML重构?
抽象地讲,HTML重构的可以让代码更能适应变化,应对系统和领域需求为新功能的开发提供更优秀的基础。
具体地讲,HTML重构可以:
- 让代码更具有可读性,更容易理解
- 重构过程中往往有意外的收获:发现隐藏的系统Bug
- 增强页面可用性, 关注点从设计者开发者转移到使用者
- 缩短提高页面的呈现时间(Slow pages -Rendering Times)
- 解决页面浏览器不兼容问题
- 搜索引擎优化Search Engine Optimization
进行HTML重构的时机?
- 每一次进行重新设计之前;新功能将构建在一个更稳固的基础之上
- Refactor When You Need to Fix a Bug
- Refactor As You Do a Code Review
- 一个原则:勿以善小而不为;重构的过程往往是断断续续的,很少有一个连续的时间给我们进行重构。所以我们只要有机会进行重构,就动手去做吧
HTML重构的目标(What Refactor To) ?
- XHTML
理由:XHTML更加严格,浏览器不再解析乱作一团的标签而是格式规范的页内容,这时负担从浏览器转移到页面开发者。内容聚合,搜索引擎优化,样式表都可以更好的应用基础。开发者能够更容易调试和解决问题,因为问题更容易定位了。XHTML不能完全解决浏览器兼容问题,但是它能够消除大部分的浏览器不兼容问题已经居功甚伟。主流HTML编辑器都提供对XHTML的支持。XHTML是未来Web应用提供坚实的基础,如:MathXML MusicXML SVG。
- CSS
理由:将展现层从内容中分离出来。为不同的阅读者提供高可读性。减少代码重复,节省带宽。
REST(Representational State Transfer表述性状态转移)是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。REST提出了一些设计概念和准则:
1.网络上的所有事物都被抽象为资源(resource);
2.每个资源对应一个唯一的资源标识(resource identifier);
3.通过通用的连接器接口(generic connector interface)对资源进行操作;
4.对资源的各种操作不会改变资源标识;
5.所有的操作都是无状态的(stateless)。
REST之所以能够提高系统的可伸缩性,是因为它强制所有操作都是stateless的,这样就没有context的约束,如果要做分布式、做集群,就不需要考虑context的问题了。同时,它令系统可以有效地使用pool。REST对性能的另一个提升来自其对client和server任务的分配:server只负责提供resource以及操作resource的服务,而client要根据resource中的data和representation自己做render。这就减少了服务器的开销。
重构的目标不是金科玉律,你没有必要逐一进行实践。你可以按照XHTML->CSS-->Rest的顺序按部就班步步为营,也可以根据实际情况调整重构目标和计划。但是只要你做了,你就可以从重构过程中得到好处。
面对质疑:还要重构么?
重构的本质决定了它不是生产性的,重构的完成并没有新功能的产生。所以重构往往面临来自各方面的质疑:
面对质疑我们给出这样的答案:
- HTML重构从长远来看为后续开发提供了一个良好的基础,实际上是节省了时间。因为系统更容易添加新功能,更容易维护。重构的过程能让开发者对以前的工作有一个思考,对新人是一个熟悉系统的机会。
- HTML重构本身并不会占用太多的时间,因为我们有很多自动化的工具可用。
- HTML重构不需要一个连续的时间,断断续续的时间未尝不可,对于开发者来说,进行重构就像日行一善。
HTML重构:战略篇
HTML重构:战术篇
HTML重构:工具篇
Tags: html, 重构
PHP | 评论:3
| 阅读:21908
Submitted by gouki on 2009, April 21, 9:16 AM
这个东西,我实在不知道放在哪个分类了。。但因为我是用PHP进行开发的,因此我还是将它归为PHP分类
昨天在Yhustc的博客上看城管操作手册,结果顺便看到了这个免费的webservice列表。
yhustc的博客功能越来越强大了,支持直接的ID的文章,现了也支持这种以英文名为路径的文章了,等再强一点,我也考虑换成yblog,哈哈,不过,要等他写转sablog的程序(实在是2.0到现在都没有出来,等的心急了)
对于sablog,我在另外的应用里,已经将它的模版机制全部转为discuz的,因为自己熟悉DZ的模版,改起来更快了。只是不知道何年才会派上用场。。。。
废话说了这么多,上重点的:
某网站支持
国内手机号码归属地查询WEB服务
2400多个城市5日天气预报 WEB服务
股票行情数据 WEB 服务(支持香港、深圳、上海基金、债券和股票;支持多股票同时查询)
中国电视节目预告(电视节目表)
火车时刻表 WEB 服务
IP地址来源搜索 WEB 服务
等等...
是什么网站呢?Look。。。
http://www.webxml.com.cn/zh_cn/web_services.aspx
其他两种我不懂,但wsdl我还是懂的。啥时候有空看看,oh yeah
Tags: webservice
PHP | 评论:0
| 阅读:25858
Submitted by gouki on 2009, April 13, 12:19 PM
放在PHP栏目是我仔细想过的,虽然文章内容里并未提及到PHP
开发WEB,很多人在一开始就考虑了优化优化再优化,但是,如果按照你这样的优化下去,当你发现瓶劲的时候你怎么办?你已经无法优化了。。
因此,为自己的代码预留一点优化空间,先赶着把代码上线,然后再边运行边优化。一来也保证了上线的时间,二来也可以在运行时注意到哪些地方是需要重点优化的。
以下内容来自守望轩(博客园)的文章:原文http://www.cnblogs.com/xjb/archive/2009/04/13/no-premature-optimization.html
Donald Knuth说“过早优化是万恶之源”(premature optimization is the root of all evil)。这话也许有些夸张,但“过早优化”的危害我觉得不能忽视。同时,我觉得“过早优化”的概念不专属编写程序,生活中的示例也比比皆是。不信,你看看下面这些情形你是否遇到过:
http://www.watch-life.net/life-thinking/no-premature-optimization.html
1、当你开始学一门程序语言的时候(比如c#),你想如果可以精通开发工具(比如Visual Studio)一定如虎添翼,于是一开始你就花很多时间去研究开发工具,而忘记自己学习的重点是语言本身,而非工具。或者,一开始,你花不少的时间去选择哪门程序语言,比较各种语言的优劣,在五花八门的语言前面犹豫不决,这个想学,那个也不想放弃,结果都是学个半路子。
2、当你学习一门外语比如英语的时候,一开始,你花了很多的时间去下载有关英语资料,花了很多的时间去找英语书籍,以为有了这些资料和书籍就可以学好英文,而不是一开始就踏踏实实的从单词、语法开始,结果后来资料下载了一大堆,书籍买了不少,却没有坚持下去。
3、你想搞体育锻炼,比如打羽毛球,于是一开始你花大量时间去买球衣、球鞋、球拍等装备,可没连几天,你发现自己开始三天打鱼了,最后,那些装备都起了灰,也没锻炼几次。
4、你想做时间管理(Getting Things Done),于是你研究各种时间管理的资料,上各种时间管理技巧的网站,比如lifehack、 digg 、gtdlife,下载对最流行的GTD的管理软件,以节省时间的名义浪费时间,很浮躁,不能做到实实在在把每天的计划都落实,拖拖拉拉。
5、你有没有这样的体验,一本书你总是对开头的部分看的最仔细,后面的章节没坚持看下去,下次又重复这种循环。当你计划做一件事的时候,总是规划的 非常完美,几乎考虑每个细节,但却没有认认真真、一步一步执行,或者过早完美计划,反而让你缩手缩脚,犹豫不前,瞻前顾后,顾此失彼,最后虎头蛇尾。
6、比如,如果我有了钱,我就如何如何享受快乐,比如,如果我将来有了很多的时间,我就会花更多的时间陪家人或锻炼…
这样类似的例子还可以举很多。
过早优化对大的问题在于:过早关注不重要的部分,而忽略行动和目标本身。以静态的思维来优化,殊不知,事务发展总是动态的,“优化”是需要长期的实 践积累才可以获得。出发点是好的,但往往好心办坏事,折腾大量的时间,做了很多不该做的,而该做的、重要的反而没做。强化外部条件、工具等外在,而忽略内 在因素和行动本身,或者,过多期望将来,而忽略当下眼前。
活在当下,实实在在做好手头的事,是避免“过早优化”最好的方法之一。
Tags: 优化
PHP | 评论:0
| 阅读:19311
Submitted by gouki on 2009, April 8, 7:31 AM
这是一个比较老的分词程序,原文中的一些链接现在不是地址不正确就是打不开了。由此可以证明它是多老了。
再加上PHP直接进行分词的性能本来就不咋地,因此,建议仅仅用在很小的地方,比如自动添加TAG之类的。
原文如下:http://blog.sina.com.cn/s/blog_5677bc54010000i5.html
用PHP去做中文分词并不是一个太明智的举动, :p
下面是我根据网上找的一个字典档, 简易实现的一个分词程序.
(注: 字典档是gdbm格式, key是词 value是词频, 约4万个常用词)
代码请参见http://www.shi8.com/out/support/art_316.txt
PHP代码
- <?php
-
-
-
-
-
-
- function getmicrotime(){
- list($usec, $sec) = explode(" ",microtime());
- return ((float)$usec + (float)$sec);
- }
- $time_start = getmicrotime();
-
-
-
- class ch_dictionary {
- var $_id;
-
- function ch_dictionary($fname = "") {
- if ($fname != "") {
- $this->load($fname);
- }
- }
-
-
- function load($fname) {
- $this->_id = dba_popen($fname, "r", "gdbm");
- if (!$this->_id) {
- echo "failed to open the dictionary.($fname)<br>\n";
- exit;
- }
- }
-
-
- function find($word) {
- $freq = dba_fetch($word, $this->_id);
- if (is_bool($freq)) $freq = -1;
- return $freq;
- }
- }
-
-
-
- class ch_word_split {
- var $_mb_mark_list;
- var $_word_maxlen;
- var $_dic;
- var $_ignore_mark;
-
- function ch_word_split () {
- $this->_mb_mark_list = array(","," ","。","!","?",":","……","、","“","”","《","》","(",")");
- $this->_word_maxlen = 12;
- $this->_dic = NULL;
- $this->_ignore_mark = true;
- }
-
-
- function set_dic($fname) {
- $this->_dic = new ch_dictionary($fname);
- }
-
- function set_ignore_mark($set) {
- if (is_bool($set)) $this->_ignore_mark = $set;
- }
-
-
- function string_split($str, $func = "") {
- $ret = array();
-
- if ($func == "" || !function_exists($func)) $func = "";
-
- $len = strlen($str);
- $qtr = "";
-
- for ($i = 0; $i < $len; $i++) {
- $char = $str[$i];
-
- if (ord($char) < 0xa1) {
-
- if (!emptyempty($qtr)) {
- $tmp = $this->_sen_split($qtr);
- $qtr = "";
-
- if ($func != "") call_user_func($func, $tmp);
- else $ret = array_merge($ret, $tmp);
- }
-
-
- if ($this->_is_alnum($char)) {
- do {
- if (($i+1) >= $len) break;
- $char2 = substr($str, $i + 1, 1);
- if (!$this->_is_alnum($char2)) break;
-
- $char .= $char2;
- $i++;
- } while (1);
-
- if ($func != "") call_user_func($func, array($char));
- else $ret[] = $char;
- }
- elseif ($char == ' ' || $char == "\t") {
-
- continue;
- }
- elseif (!$this->_ignore_mark) {
- if ($func != "") call_user_func($func, array($char));
- else $ret[] = $char;
- }
- }
- else {
-
- $i++;
- $char .= $str[$i];
-
- if (in_array($char, $this->_mb_mark_list)) {
- if (!emptyempty($qtr)) {
- $tmp = $this->_sen_split($qtr);
- $qtr = "";
-
- if ($func != "") call_user_func($func, $tmp);
- else $ret = array_merge($ret, $tmp);
- }
-
- if (!$this->_ignore_mark) {
- if ($func != "") call_user_func($func, array($char));
- else $ret[] = $char;
- }
- }
- else {
- $qtr .= $char;
- }
- }
- }
-
- if (strlen($qtr) > 0) {
- $tmp = $this->_sen_split($qtr);
-
- if ($func != "") call_user_func($func, $tmp);
- else $ret = array_merge($ret, $tmp);
- }
-
-
- if ($func == "") {
- return $ret;
- }
- else {
- return true;
- }
- }
-
-
- function _sen_split($sen) {
- $len = strlen($sen) / 2;
- $ret = array();
-
- for ($i = $len - 1; $i >= 0; $i--) {
-
-
-
- $w = substr($sen, $i * 2, 2);
-
-
- $wlen = 1;
-
-
- $lf = 0;
- for ($j = 1; $j <= $this->_word_maxlen; $j++) {
- $o = $i - $j;
- if ($o < 0) break;
- $w2 = substr($sen, $o * 2, ($j + 1) * 2);
-
- $tmp_f = $this->_dic->find($w2);
-
- if ($tmp_f > $lf) {
- $lf = $tmp_f;
- $wlen = $j + 1;
- $w = $w2;
- }
- }
-
- $i = $i - $wlen + 1;
- array_push($ret, $w);
- }
-
- $ret = array_reverse($ret);
- return $ret;
- }
-
-
- function _is_alnum($char) {
- $ord = ord($char);
- if ($ord == 45 || $ord == 95 || ($ord >= 48 && $ord <= 57))
- return true;
- if (($ord >= 97 && $ord <= 122) || ($ord >= 65 && $ord <= 90))
- return true;
- return false;
- }
- }
-
-
-
- function call_back($ar) {
- foreach ($ar as $tmp) {
- echo $tmp . " ";
-
- }
- }
-
-
- $wp = new ch_word_split();
- $wp->set_dic("dic.db");
-
- if (!isset($_REQUEST['testdat']) || emptyempty($_REQUEST['testdat'])) {
- $data = file_get_contents("sample.txt");
- }
- else {
- $data = & $_REQUEST['testdat'];
- }
-
-
- echo "<h3>简易分词演示</h3>\n";
- echo "<hr>\n";
- echo "分词结果(" . strlen($data) . " chars): <br>\n<textarea cols=100 rows=10>\n";
-
-
- $wp->set_ignore_mark(false);
-
-
- $wp->string_split($data, "call_back");
-
- $time_end = getmicrotime();
- $time = $time_end - $time_start;
-
- echo "</textarea><br>\n本次分词耗时: $time seconds <br>\n";
- ?>
- <hr>
- <form method=post>
- 您也可以在下面文本框中输入文字,提交后试验分词效果:<br>
- <textarea name=testdat cols=100 rows=10></textarea><br>
- <input type=submit>
- </form>
- <hr>
文章引用自:http://www.im286.net/viewthread.php?tid=1157015
Tags: 分词, gbm
PHP | 评论:0
| 阅读:20350