leechael.orgHome

OO in PHP (3)

让我们首先欢呼,良好的学术气氛万岁。 :P

先看看 fcicq 同学在 上一篇 后面的留言。既然有同学提出不同的看法,我们就去看看对比的结果。

测试环境: Windows XP sp2, WAMP5 1.7.2 (Apache 2.2.4, PHP 5.2.3), CPU Inter T2050 @ 1.6GHz。两个脚本分别运行一万次,计算运行耗时及内存使用情况。

第一次测试

Tradition:
Time Usage: 1.05502605438
Memory Usage: 66368

Linked:
Time Usage: 1.10734796524
Memory Usage: 69344

第二次测试

Tradition:
Time Usage: 1.04215908051
Memory Usage: 66368

Linked:
Time Usage: 1.0259718895
Memory Usage: 69344

重启 apache,第三次测试

Tradition:
Time Usage: 0.997123003006
Memory Usage: 66616

Linked:
Time Usage: 1.10502290726
Memory Usage: 69344

第四次

Tradition:
Time Usage: 1.04014492035
Memory Usage: 66368

Linked:
Time Usage: 1.08955287933
Memory Usage: 69344

Conclusion

一万次的运算才带来 0.1 秒的差别,我想利用 OO 打造 Validator 带来的便捷以及更少的代码量,我想大家会从中平衡两者的关系?

再唠叨两句:OO 相应而至的内存使用量(php.ini 中的 memory_limit 记得调整至合适的值),以及实际情况中是否需要牺牲时间来获得如此这般的灵活性(不需要假设你的代码会面临的情况有多么严峻,每秒钟超过 10 requests?),exception 是昂贵的。

测试中的代码可以在这里下载,有兴趣的朋友可以自己试试看: http://leechael.org/files/validator.tar.bz2

Update

经 fcicq 同学指点,改进了脚本,重新测试后的结果:

Tradition
Time Usage: 0.43701004982
Memory Usage: 67512

Linked
Time Usage: 0.607961893082
Memory Usage: 71712

这次的数字可能带来的心理影响不同: 0.17s。最起码 6 看起来比 4 大。 :D

Update 2

作为我还不足够严谨的证明,所以加上这个 Update。如下面 Cofyc 所言,对于 PHP Programmer 来说,更重要的是寻找到一个平衡点,因为 OO 只会带来开发上的便捷,而不是脚本运行速度上的提升。

Unobtrusive JavaScript: To Be or Not To Be

印象中国内并没有多少人会提及 Unobtrusive JavaScript(低调的 JavaScript/不乱入的 JavaScript, 前者是在国内一 blog 看见的翻译,后者是对岸的一位设计师 Othree 的翻译)。本来这也不是很大的问题,倡导 CSS/JavaScript/HTML 代码分离是很多设计师们倡导的事情。有一篇 The seven rules of Unobtrusive JavaScript 说了七点 Unobtrusive JavaScript 要注意到的事情:

  • 不作任何假定。
  • 找到你的 JavaScript 在 HTML 代码中的接入点及与其的关系
  • 将遍历 (Traversing) 留给专家(利用 CSS 来找寻你需要的元素)
  • 了解浏览器和用户
  • 了解事件(Events)
  • 不与其他代码冲突
  • 为下一个开发者工作

在看到最后一点后,一些东西就不再奇怪了。Unobtrusive JavaScript 倡导了一种良好的编码习惯,而实际上,或者说一句不中听的,这是给代码工人的规则。

Plaxo 的 Joseph Smarr 有一个很棒的、关于提高 JavaScript 的 slides: High Performance JavaScript。其中说到: Directly attach onclick, etc. handlers instead using event listeners where appropriate(尽可能地直接使用 onclick 等控制事件而不是事件冒泡).原因很简单,因为 Finding by class/attaching event handlers is slow.例如我需要那些 class 为 pop 的链接在点击后自动打开新窗口,当然我们可以通过编写一个额外的脚本来监控这些链接的点击,但在这些链接中使用 onclick 会让脚本运行得更快,但维护起来也会很麻烦。

而事实上,我们是否需要这般完整的分离代码呢?很大的可能是看这个站点对 JavaScript 的依赖程度。如果是轻度使用 JavaScript 来增强用户体验,Unobtrusive JavaScript 是很好的习惯;如果是那些 Web Application,例如,由于需要更多地考虑 JavaScript 的执行效率,就不必碍于 Unobtrusive JavaScript 的规则,适当地在 HTML 代码中插入 JavaScript 代码也未尝不可。

深究起来,其实这和编程中常见的、关于程序的 scalability 和 performance 的衡量,没有什么区别。

echo(), postscript

在上一篇 echo() 发布后, fcicq 就来添乱子了。 :D

$s = microtime(true);
echo str_repeat('Must I write something here? I don\'t know. But I need some characters for testing.<br />', 100000);
$e=microtime(true);
echo '<br /><br /> . ($e-$s);

0.0314919948578

$foo = array_fill(0, 100000, 'Must I write something here? I don\'t know. But I need some characters for testing.<br />');
$s = microtime(true);
$bar = implode('', $foo);
echo $bar;
$e=microtime(true);
echo '<br /><br /> . ($e-$s);

0.371160984039

用 str_repeat() 来循环同一个句子, 以及 implode() 来合并数组。首先说的是,str_repeat() 的表现很好,但却不是想要的: 没有人会在页面中呈现同一个句子,除非是 spammer。而implode() 的成绩与 for loop 相近。

echo()

做了一个小测试, 测试 echo 的性能: 循环 100000 次输出同一个句子。第一个脚本使用每一次循环都调用一次 echo(); 而第二个脚本则是通过修改一个变量,循环结束后输出结果。测试中分别使用了 if, while, do-while 三种循环方式。

第一个脚本的结果在前,第二个脚本的结果在后,单位是秒。

if loop: 5.05437803268 - 0.375290155411
while loop: 5.26496505737 - 0.417444944382
do-while loop: 6.0743200779 - 0.379925966263

试验过程简略记录在 v2ex, 有需要的同学可以 翻墙查看

我的结论是, 尽量避免大量使用 echo()。例如,为了源代码单行代码更短,一般我们都是这般:

echo('Must I write something here?');
echo(' I don\'t know.');
echo('But I need some characters for testing.<br />');

而实际上,从代码的可读性出发,我们可以考虑这般的写法:

$str = '';
$str .= 'Must I write something here?';
$str .= ' I don\'t know.';
$str .= 'But I need some characters for testing.<br />';
echo($str);

此外, 也能看出 if loop 比 do-while loop 更常用,而 do-while loop 只能坐冷板凳的原因,在 do-while loop 的测试中也大致能看出来。

有一点需要提醒的是,注意 do-while 的不同: 先执行, 再判断是否达到跳出循环的条件。