三月底在上海 PEA 聚会上做了次关于“PHP 运行机制”的演讲,附件是演讲时用的幻灯片。这次演讲我给自己打 70 分,后面发挥得还不错,但整体上感觉内容组织还有改善的余地,演讲时有些话都重复了好几次,环视全场的机会也不多,以后有机会要注意改正。

ps:
其实单独看幻灯片估计也看不出什么东西来:D,有机会要把当时谈的内容给整理一下再发个 paper 上来。

《PHP 运行机制初探》幻灯片下载

FreeBSD 7.0 昨日正式发布了,最大的亮点就是改善了 SMP 环境下负载能力。官方说相对于 6.x 普通负载下性能提高了 350%,高负载下性能提高了 1500%。如果能得到证实的话,那这些数据可真是相当的恐怖!

出于保守策略,ULE 调度器没有在 7.0 中作为默认的调度器,可能需要重新编译一下内核。GCC 4.x 的引入和 ZFS 文件系统的试验性支持也是让人值得兴奋。

我已经下载下来并在一部机器上试运行了,感觉良好~ :)

抽空编译了这个 windows 版(附件已更新为 1.0.0 版链接)。这个版本主要是根据 hightman 大牛的 xNix 代码 移植而来。主要改动集中在处理了一些 GCC 与 VC 的兼容性代码,Lock 部分借鉴了 PHP 在跨平台方面的一些成果,去掉了 MMAP 支持,改为普通文件操作。

点击下载 SCWS 扩展 PHP 4.4.x 版二进制文件

点击下载 SCWS 扩展 PHP 5.2.x 版二进制文件

点击下载 SCWS 扩展源码及 VC6 工程文件

点击查看 SCWS - 简易中文分词系统简介

源码分析,首先得看源码。记事本可以看,EditPlus 也可以看,但显然具有语法着色功能的 EditPlus 要比记事本爽。更显然,M$ 的 Visual C++ 比 EditPlus 还要爽。:D 因此我推荐的第一款神兵就是 M$ Visual C++(Sorry, Linuxer~)。既然用了 Visual C++ 那么有一款它的插件我们不得不提:Visual Assist X,还没有她的朋友尽快拥有她吧~

OK,现在源码是可以看了,而且是很舒服地在看,但有时我们还想实地进行单步调试以一窥究竟。要调试自然得先编译。很不幸,PHP 在 Windows 环境下的编译和调试并不像想象中的那么简单。我们至少得比在 xNix 环境下多做一下几个步骤:

  1. 下载 PHP 使用的 DNS 解析器的源代码(http://www.php.net/extra/bindlib_w32.zip)并将其编译输出一个名为 resolv.lib 的库文件。
  2. 下载 win32 编译工具 http://www.php.net/extra/win32build.zip ,解压至某一目录(假定为 $work)。在 $work\lib 目录里面也有个 resolv.lib,我们把步骤 1 产生的 resolv.lib 复制到这个目录,覆盖之。
  3. 设置编译环境。把 $Work\bin 添加到系统 PATH 环境变量和 Visual C++ 的 Executable files 目录;把 $work\lib 添加到 Library files 目录;把 $Work\include 添加到 Include files 目录。
  4. 下载 PHP 源文件并解压至 $work 。
  5. 整理 PHP 的项目工程文件。PHP 4.x 的 VC 工程文件($PHP\win32\php4ts*.dsw)是当时一直在维护的,因此可以直接拿来就用。PHP 5.x 增加了一种新的基于命令行的类 Unix 编译系统,使得编译 PHP 更为简单。于是相应的工程文件 php5ts*.dsw 便不再被 PHP 团队维护,也不能直接使用编译 PHP 5 了。但我们恰恰不想单纯的编译,我们想的是在 Visual C++ 里面进行编译然后下断点单步调试,因此我们就需要命令行编译系统的编译流程重建这个项目工程文件(可能还需要对某些文件做些必要的改动)。

为方便大家不做重复性劳动,我把我现在用的 PHP 调试环境打包发上来,大家下载后直接解压到某一目录即可。所需另外做的也只是根据你解压的目录设置一下编译的环境变量(见步骤 3),之后就可直接进入 $work\win32 打开 php5ts.dsw(VC6)或 php5ts.sln(VC2005)。

点击下载该 PHP win32 AllinOne 包。

工程文件说明:这其实是个“精简版”PHP 的工程文件,里面的 PHP 是 php 5.2.1 的源码,但只包含 date、reflection、session、standard 这四个内建扩展。另外 php5apache2 的 sapi 不能编译,要想编译它得再去下一份 Apache 2 的源码。除此之外还删除了大部分的测试脚本。

最后再说一下分析 PHP 源代码所需要一些基础知识。首先当然得有一定的 C 语言基础。在最后分析 Zend Engine 时可能还需要一些编译器方面知识,最好能看懂一些 lex&yacc 的语法文件(PHP 采用的是 flex 和 bison,但在语法层面相差无几)。最后是能有一定的调试技术。包括在 VC++ 环境下的有源码调试技术和无源码的二进制代码调试技术(这种情况下我一般用OllyDbg)。其中 C 语言基础是必须的,而后面的两种知识/技术则可有可无,但有的话可以达到事半功倍之效。

目前在 PHP 社区尤其是国内的 PHP 社区对 PHP 内核这方面讨论的比较少。我平时常看一些 PHP 源码,对 PHP 的运行机制算是有一些认识吧,因此我打算写一些这方面的文章,算是抛砖引玉。最终目标我希望可以做成一个关于 PHP 内核的中文百科全书。应该说这是一个不算太小的工程,依我个人之力几乎不可能完成。更何况老子曾经曰过:“知者不言,言者不知”,相信潜在水下面的大牛(水牛?^_^)还有 N 多。所以希望大家群策群力,共同完成这个项目。

整个项目我初步打算以 PHP 5.2.x 的源码为研究对象,侧重于对 Zend Engine 的表述,兼顾一些 SAPI 层。下面是我列出的一份清单,大家看看还有没有什么遗漏或者内容编排不合理之处。请诸位畅所欲言,有啥说啥,即使跑题也没关系~ :D 

    PHP 源代码分析 V0.0.1

    第一章 构建系统
  1. 准备工具、库及需要具备的基础知识;
  2. 如何编译不同平台的版本?编译时的各个选项是什么含义?
  3. 如何创建一个 PHP 扩展/模块?如何创建一个 Zend 扩展?
  4. 如何调试 PHP?如何调试 PHP/Zend 扩展?
    第二章 PHP 与 SAPI 的生命周期
  1. 脚本的运行周期,一切从 main() 开始;
  2. 模块/脚本的起始与终止函数;
  3. PHP SAPI 协议;
  4. 嵌入式 PHP 设计。
    第三章 内存管理
  1. Zend 的内存管理器框架;
  2. 内存申请与释放流程,垃圾回收;
  3. 持久化(persistence)
    第四章 线程安全
  1. 为何会有这个问题?Zend Engine 是如何解决的?
  2. 我是否该启用 ZTS?各有什么优缺点?
  3. 如何构建一个 ZTS 的程序/扩展?
    第五章 变量与常量
  1. PHP 中的数据类型。
  2. 变量、常量与静态变量。
  3. 引用计数机制;
  4. 资源的创建与回收;
  5. 未来字符串的 UNICODE 支持、JIT 支持。
    第六章 函数
  1. 函数的内部布局;
  2. 函数的定义;
  3. 如何获取函数的参数。可选参数、参数默认值;
  4. 函数的返回值;
    第七章 类与对象
  1. 类的内部布局(属性、方法);
  2. 构造函数与析构函数;
  3. 类的继承与转换(up casting 与 down casting);
  4. 接口(轻量级的类),微观上与类的差别;
  5. 类之间的up casting 和 down casting。
  6. stdClass。
    第八章 错误与异常
  1. 什么是错误、什么是异常。两者的区别;
  2. 如何创建和抛出异常;
  3. try/catch 的设计与实现;
    第九章 流(Streams)支持
  1. 这方面我接触较少,内容待定;
    第十章 虚拟机
  1. 脚本编译机制(词法分析、语法分析);
  2. 脚本的执行机制(CALL|SWITCH|GOTO);
  3. 各个符号表的作用;
  4. 开发 OPCode 缓存器;
  5. 开发 PHP 调试器;
    附录
  1. 完整的 PHP API、Zend API 以及宏(Micro)参考(长期工程)
  2. Zend Engine 1 的主要特性,与 Zend Engine 2的主要差别;
  3. Zend Engine 3 的主要特性,与 Zend Engine 2的主要差别;
  4. 相关资源

项目发起:Ben
项目参与:Ben (ben.yan at msn dot com,http://www.yAnbiN.org
项目启动:2007/06/09 (希望可以在明年奥运会开幕前完成 :D)
项目进度:

  1. 2007/06/09 项目启动,讨论项目规划;
  2. 2007/xx/xx 待续……

以前每当一个 ZendStudio 的新版本发布时都会同时发布一个新版的 ZendStudioServer 组件,这个组件可以让我们很方便地进行远程调试。但是自从 Zend 发布了 ZendPlatform 以后他们就不再更新 ZendStudioServer 组件了。这就导致我们只能远程调试 PHP 5.1.x 的环境,而不能调试 PHP 5.2.x。要想调试 PHP 5.2.x 只能装一个庞大的 ZendPlatform。:(

因此我一直在找一个“轻量级”的解决方案。近日在逛 Zend.com 时发现了一个好东西:ZendDebugger-5.2.3-Windows-i386.zip,直觉告诉我,这就是我想要的。果不其然,今天试验成功!

下面就说一说我的试验步骤:

  1. 到这里下载 ZendDebugger-5.2.3-Windows-i386.zip,然后将其解压到某一目录,比如:C:\Program Files\Zend,这就会在该目录里面新建一个 ZendDebugger-5.2.3-Windows-i386 子目录,里面有 4_3_x_comp、4_4_x_comp、5_2_x_comp 等目录,将这些 x_y_z_comp 分别改为 php-x.y.z(比如将目录 5_2_x_comp 改为 php-5.2.x);
  2. 确保已经加载了 Zend Extension Manager,如果安装了 Zend Optimizer 则会自动安装 Zend Extension Manager,若没有安装请先安装 Zend Optimizer 。或者你可以把 Zend Optimizer 中 ZendExtensionManager.dll 给提取出来,然后手工在 php.ini 中添加一行:
    zend_extension_ts=”C:\Program Files\Zend\ZendOptimizer\ZendExtensionManager.dll”
    其中 ZendExtensionManager.dll 的位置请根据你的实际情况填写;
  3. 在 Web Server 的 php.ini 添加下面几行:
    zend_extension_manager.debug_server_ts=”C:\Program Files\Zend\ZendDebugger-5.2.3-Windows-i386″
    zend_debugger.expose_remotely=allowed_hosts
    zend_debugger.allow_hosts=127.0.0.1/32,192.168.1.0/24,192.168.1.0/24
    zend_debugger.allow_tunnel=127.0.0.1/32

    zend_extension_manager.debug_server_ts 的值请根据你的实际情况填写,就是 php-x.y.z 的父目录。

  4. 把 ZendDebugger-5.2.3-Windows-i386 目录下的 dummy.php 复制到你的 Web 站点根目录。

  5. 重启你的 Web Server,OK!

 简单总结一下:Zend Studio 的远程调试是由 ZendStudioServer 组件(ZendDebuger.dll)提供的。本质上这是一个 Zend 扩展,因此你只要能把这个 Zend 扩展启用就可以了。只是 Zend 公司出品的 Zend 扩展只能由那个 Zend Extension Manager 负责加载,所以我们才需要做一些额外的步骤,否则只需简单地加一行 zend_extension_ts = xxxxxx 而已。

Zend Extension Manager 是一个 Zend 公司用于统一管理该公司出品的各种 Zend 扩展的 Zend 扩展。一般来说 Zend 扩展都是高度依赖 Zend Engine 版本的,但是 Zend Extension Manager 却可以不依赖任何具体版本的 PHP 运行库,并且会根据不同的运行环境自动加载不同产品相应版本的 Zend 扩展。相信通过学习 Zend Extension Manager 的实现会对我们统一开发部署 Zend 扩展提供一些帮助。

附件就是 Zend Extension Manager v1.2.0 版本的源代码和 VC++ 工程文件。源码是根据 ZendOptimizer-3.2.8-Windows-i386 中的 ZendExtensionManager.dll 逆向出来的。编译出来的 ZendExtensionManager.dll 可完全替代原始文件(事实上也没有任何区别)。

点击下载源码

php|tek 是由《php|architect》杂志主办的重量级 PHP 专业盛会。虽然不能到场亲自聆听大牛们的演讲(事实上像我这种鸟语菜菜到了也不一定能听得懂。:-(),但看看他们演讲时提纲挈领的幻灯片也是可以管窥到很多有价值的信息的。下面是我收集到的大会上这些大牛们的幻灯片,供感兴趣的朋友参考:

演讲人 演讲主题
Aaron Wormus Moving to PHP5 with Style
Brian Shire APC @ Facebook
Caroline Maynard Services made simple with PHP
Chris Hartjes What Can PHP Learn From Ruby on Rails?
Derick Rethans Help, I Found a Bug in my Code!
Derick Rethans Exposing Hidden PHP Secrets
Ilia Alshanetsky High Performance PHP
Ilia Alshanetsky Securing PHP Applications
Ilia Alshanetsky PHP Security Pitfalls
Jason Sweat Test Driven Development
Jason Sweat Design Patterns
Jay Pipes Top 15 Ways to Kill MySQL Performance
Jeff Griffiths PHP, Remote XUL and jQuery
Jeff Moore Writing Maintainable PHP Code
Jeff Moore Dependency Injection in PHP
Jeff Moore Exceptional PHP
Marcus Boerger Introducing Phar
Marcus Boerger The Standard PHP Library
Paul Reinheimer Zend PHP 5 Certification Crash Course
Rasmus Lerdorf PHP on Hormones
Sara Golemon PHP Extension Writing
Sebastian Bergmann Testing PHP/Web Applications with PHPUnit 3 and Selenium

《Zend API,深入 PHP 内核》一章的初译暂时算是告一段落了。整个翻译进度前快后慢,这主要是和我本人的水平有很大关系的,同时也略微夹杂着一丝“翻译疲劳”。不过翻译的过程也是学习的过程。有很多地方都是平时囫囵吞枣,得过且过的,但这次为了翻译出去不误人子弟,被迫将所有的知识点都串联理顺了一下,自己感觉也有了很大的提高。

以后半个月或一个月我会再对初译稿进行一些审定,有些术语也尽量统一起来。整个翻译的行文现在看起来还是有点晦涩,还没有摆脱技术译稿的感觉,所以在这一点也须做些润色。在复审之后我会尝试将这些翻译提交到 PHP 手册的中文文档组,以便让更多的 PHPer 在做这方面的工作时有一点点中文参考。

同时在翻译的过程中也有了一些自己的看法,有机会再另行一些文章和大家交流。

下面(见表3.19 访问 zval 容器的 API 宏)是一些引入到 Zend API 里面用于访问 zval 容器的 API  宏。

指向
Z_LVAL(zval) (zval).value.lval
Z_DVAL(zval) (zval).value.dval
Z_STRVAL(zval) (zval).value.str.val
Z_STRLEN(zval) (zval).value.str.len
Z_ARRVAL(zval) (zval).value.ht
Z_LVAL_P(zval) (*zval).value.lval
Z_DVAL_P(zval) (*zval).value.dval
Z_STRVAL_P(zval_p) (*zval).value.str.val
Z_STRLEN_P(zval_p) (*zval).value.str.len
Z_ARRVAL_P(zval_p) (*zval).value.ht
Z_LVAL_PP(zval_pp) (**zval).value.lval
Z_DVAL_PP(zval_pp) (**zval).value.dval
Z_STRVAL_PP(zval_pp) (**zval).value.str.val
Z_STRLEN_PP(zval_pp) (**zval).value.str.len
Z_ARRVAL_PP(zval_pp) (**zval).value.ht

Next Page »