风雪之隅
msgbartop
PHP源码分析,Zend引擎分析,Web技术分享–左手代码 右手诗
msgbarbottom

16 Aug 08 扩展PHP[Extending PHP](一)

这篇文章将会系统的介绍如何开发自己的PHP扩展, 也许你会说,网上这样的文章已经很多了,为什么还要写? 呵呵,我当然不会只是简单的重复。 这篇文章将会涉及到很多的高级技术,比如在自己的扩展中使用资源,开发一个类给脚本使用,在PHP中使用C++的对象等等,另外这篇文章还会穿插很多Zend引擎和PHP内核的知识,比如变量的实现,资源的实现,PHP4和PHP5对类的不同实现等等

首先,我们要有个认识,那就是在php中的类和函数,以至于变量,在本质上都是C实现的。 你所编写的脚本,最终都会被转换成C代码来执行。 这个和我在以前文章中(深入理解PHP原理之Opcodes)介绍的opcode并不冲突, 因为Zend虚拟机的指令最终还是要翻译成C代码来执行。

开发者也就可以使用C/C++来写一些PHP的函数,类。从而扩展PHP, 那么,为什么要扩展PHP呢? 很多同学只是盲目的去扩展,认为扩展PHP是一个很有“意义”的事(许三多语气),而我认为,扩展PHP只是在特定的情况才有必要,最主要的俩个原因是:

  • 与外部的库做交互, 比如你有一个C/C++的库, 不妨假设,这个库呢就是实现了一个字符串加密和解密,而你并没有这个库的源码,也就是说,你无法把这个库在PHP中实现, 那么你只有编写一个PHP扩展,来做为一个桥梁,连接起你的PHP和这个库。
  • 效率, 不容置疑,PHP编写的脚本,比同等的C/C++编写的脚本,效率要高出很多。 当你用常见的手段,再也无法提高你的脚本的效率,而效率要求又是那么的紧迫, 那么我只能劝你, 把你的逻辑,用C/C++改写吧。。
  • 其实第二个理由,已经是很充足了,但是用扩展来实现你的逻辑,并不是那么简单的事情:
    首先如果你是使用PHP来实现你的逻辑,那么你不需要考虑资源管理,Zend会替你完成。其次你也不需要担心, 代码的一个简单的错误,就会导致PHP core dump。

    而如果你用C来编写PHP的扩展,那么你就要自己考虑这些事情,自己管理资源的分配,使用,释放。 你也要学会适应segmentation fault :)。 我要提醒你的是, 因为PHP是一个长时间运行的模块(因为Apache是一个长时间运行的Web服务器), 所以,你千万要防止资源泄露, 我就遇到过一个简单的字符串泄露, 在一段时间以后,Apache占用的内存超过了1个G。
    接下来,总结一下用C/C++扩展PHP的优缺点:
    优点:

  • 效率,还是效率
  • 减少PHP脚本的复杂度, 极端情况下, 你只需要在PHP脚本中,简单的调用一个扩展实现的函数,然后你所有的功能都就被扩展实现了,呵呵
  • 而缺点也是显而易见的:

  • 开发复杂
  • 可维护性降低
  • 开发周期变长, 最简单的一个例子,当你用PHP脚本的时候, 如果你发现某个判断条件出错,你只要修改了这一行,保存,那么就立刻能见效。 而如果是在C/C++编写的PHP扩展中, 那你可需要,修改源码,重新编译,然后重新load进PHP, 然后重启Apache,才能见效。。
  • 恩,现在你看到了, 用C/C++实现PHP扩展的优点和缺点了,那么你就可以自己权衡你的逻辑,是要用那种方式实现了。呵呵

    如果你熟悉C,那么编写一个PHP扩展,并不是什么非常难的事情。 PHP本身就提供了一个框架,来简化你的开发。

    最简单的方式来开始一个PHP扩展的开发,是使用PHP提供的扩展框架wizard ext_skel, 它会生成一个PHP扩展所必须的最基本的代码, 要使用它,首先你要下载PHP的源码,或者开发包, 进入PHP源码的ext目录, 就会发现这个工具。比如我下载了PHP源码php5.2-SRC到/home/xinchen/,那么这个工具的路径就在: /home/xinchen/php5.2-SRC/ext下。

    这个工具的使用方式也很简单, 比如我们要创建一个名叫example的扩展,那么:

    $ cd ~/php5.2-SRC/ext
    $ ./ext_skel  --extname=example
    Creating directory example
    Creating basic files: config.m4 config.w32 .cvsignore example.c php_example.h CREDITS EXPERIMENTAL tests/001.phpt example.php [done].

    To use your new extension, you will have to execute the following steps:

    1.  $ cd ..
    2.  $ vi ext/example/config.m4
    3.  $ ./buildconf
    4.  $ ./configure --[with|enable]-example
    5.  $ make
    6.  $ ./php -f ext/example/example.php
    7.  $ vi ext/example/example.c
    8.  $ make

    Repeat steps 3-6 until you are satisfied with ext/example/config.m4 and
    step 6 confirms that your module is compiled into PHP. Then, start writing
    code and repeat the last two steps as often as necessary.

    这样,就在ext目录下生成了一个名为example的目录,并在这个目录下生成了所有的要完成一个PHP扩展所必须的文件和代码(事实上,这个目录下的文件,已经可以生成一个PHP的标准扩展了,只不过这个扩展不完成任何功能,就好像我们使用Visual Studio的Wizard生成的一个空的MFC框架一样)。接下来,我们要做的就是不停的重复最后俩个步骤,从而实现我们的功能。

    在这个目录下,我们要尤其关注的是example.c这个文件,这个文件是我们扩展的主要文件,也就是说,如果我们要充实我们的扩展,那么就需要在这个文件中进行工作。 在后面的内容中,我会消息介绍这个文件中包含的各个字段,结构的含义,现在我们就只是简单的掠过他。
    第二个要特别注意的文件就是config.m4,如果读者你有过在Unix/Linux下的编程经历,那么你或许听过autoconf和m4, m4是一个宏解释工具,它会把输入文件中的宏展开到输出文件。所以这个config.m4是PHP扩展框架所必须的,也是关键的一个文件,用来生成我们扩展的makefile。
    在config.m4中,有一行:

    PHP_ARG_ENABLE(example, whether to enable example support,
     
    [  --enable-example           Enable example support])

    在m4中,dnl表示注释, 这段指令创建了一个configure时的参数“enable-example”, 第二个参数会显示在当configure处理到这个模块的configure文件的时候。第三个参数,会在用户输入./configurehelp的时候,作为一个可选的选项被显示。
    另外还有一段:

    PHP_ARG_WITH(example, for example support,
    [  --with-example             Include example support])

    严格来说,上面的俩段没有太大的区别,只不过with是说明了,要启用这个模块,必须要的先决条件,也就是说这个模块依赖于某些其他模块。
    就好像:

    <?php
    ./
    configure --with-apxs=/usr/local/apache/bin/apxs  --enable-example

    PHP的扩展框架构建系统,支持全套的.m4语法,当然还支持用户自定义的宏, 下面我介绍一些常见的,由PHP扩展框架构建系统定义的宏:

    PHP_CHECK_LIBRARY(library, func [, found [, not-found [, extra-libs]]])
          在库library中查找func是否存在,如果存在则这个宏会被展开成found,否则not-found;

    PHP_DEFINE(what, [value])
          这个就是对AC_DEFUN简单包装,最终会被展开成:
         #define what value
    PHP_REQURE_CXX
           如果你的扩展是使用C++编写,那么你就必须使用这个宏,来告诉编译器使用C++编译器。这个宏会被展开成:
          AC_PROG_CXX
          AC_PROG_CXXCPP

    更多的由PHP扩展框架构建系统提供的宏,你可以到acinclude.m4中查看。
    还有一些其他的有ext_skel创建的文件:

    CREDITES 这个文件没什么太大的作用,只是用来在发布你的扩展的时候附加一些其他信息 ,比如作者啊,等等。
    EXPERIMENTAL 这个文件只是标志说,这个扩展是实验性的,所以你可以不用管它
    example.php 这个文件是用来简单测试你的扩展的
    php_example.h 这个是我们扩展的头文件
    tests/001.phpt 这个也是个测试文件, 不过使用的是单元测试, 阶段测试, 具体内容,你打开一看便知 ;)

    下一次我讲介绍一些要开发扩展,最好要先了解的知识,比如变量的内部表示,copy-on-write , change-on-write机制, 函数的内部表示==。 当然,这其中有些知识是我以前的文章已经涉及过的:

    PHP Life Cycle演讲幻灯片

    深入浅出PHP

    深入理解PHP原理之Opcodes

    PHP的函数(Introspecting PHP Function)

    Related Posts:

    Tags: ,



    Reader's Comments

    1. |

      恩,这个文章要持续开发。

      [回复]

    2. |

      顶,学习了

      [回复]

    3. |

      很难啃,舔一舔也好

      [回复]

    4. |

      部分内容似乎在哪见过,不过写的不错,支持博主。

      [回复]

    5. |

      恩,网上有不少介绍扩展PHP的文章,;) “也许你会说,网上这样的文章已经很多了,为什么还要写?”

      [回复]

    6. |

      网上有很多类似文章,但介绍的要么过于简单,要么过于艰深,希望博主再接在励。

      [回复]

    7. |

      恩,有些内容我不会完全归类到这个系列下面,但是确实和这个系列相关的。最后我会把相关的东西整理起来,所以你可以看看我其他的文章,不一定等我归类到这个系列后再看,;)

      [回复]

    8. |

      强烈支持楼主,非常好的文章!

      [回复]

    9. |

      希望楼主继续写关于扩展方面的文章.加油!

      [回复]



    Leave a Comment