[ PHP 内核与扩展开发系列] 第一个 PHP 扩展:编译扩展

我们已经在上一节准备好了需要编译的源文件,接下来需要的便是把它们编译成目标文件了。

在 *nix 下编译安装

第一步:我们需要根据 config.m4 文件生成 configure 脚本、Makefile 等文件,这一步由 phpize 来帮我们做:

$ /usr/local/php54/bin/phpize
Configuring for:
PHP Api Version:         20100412
Zend Module Api No:      20100525
Zend Extension Api No:   220100525

现在查看一下我们扩展所在的目录,会发现多了许多文件。phpize 程序根据 config.m4 里的信息生成了许多编译 PHP 扩展必须的文件,这为我们省了很多的麻烦。接下来我们运行 ./configure 脚本:

./configure --with-php-config=/usr/local/php54/bin/php-config

这里我们并不需要再注明 enable-maintainer-ztsenable-debug 等参数,phpize 程序会自动去已经编译完成的 PHP 核心里获取这几个参数的值。

接下来就像我们安装其它程序一样执行 makemake install即可:

make
sudo make install

如果没有错误,就会将扩展生成到指定目录:

Installing shared extensions:     /usr/local/php54/lib/php/extensions/debug-zts-20100525/

加载扩展

为了使 PHP 能够找到需要的扩展文件,我们需要把编译好的 so 文件复制到 PHP 的扩展目录下,它的地址我们可以通过 phpinfo() 输出的信息找到,也可以在 php.ini 文件里进行配置找到并配置,名称为:extension_dir 的值。

我们可以通过 php -i 命令:

/usr/local/php54/bin/php -i | grep extension_dir

或者 <?php phpinfo(); 来查看当前加载的 php.ini 文件位置。其实在上述编译安装过程中系统已经自动为我们将 PHP 扩展生成到对应扩展目录了,无需更多操作即可在程序中加载使用该扩展。我们可以通过 dl 命令来将我们的扩展加载到内存中来。

<?php
    dl('academy.so');
    var_dump(get_loaded_extensions());

如果在输出中我们没有找到 academy.so,那肯定是哪里出问题了(需要注意的是,从 PHP 5.3 起,某些 SAPI 移除了对该函数的支持),这时候我们需要根据程序的输出信息去查找错误。

上面这样每次使用扩展都需要先 dl 一下真是太麻烦了,其实我们有更好的办法让 PHP 运行时自动加载我们的扩展。那就是在 php.ini 里这样配置:

extension=academy.so

这样只要我们把 academy.so 这个文件放置在 extension_dir 配置的目录下,PHP 就会在每次启动的时候自动加载了。这样我们就可以像我们平时使用 curlmysql 扩展一样直接使用,而不用调用 dl 函数了:

注:以下的章节我们都默认使用上面的这种方式来加载我们的扩展,而不是调用 dl 函数。

静态编译

我们检查一下 PHP 语言中 get_loaded_extensions() 函数的输出,会发现有一些扩展并没有在php.ini 文件中配置,而它们确实也已经加载到 PHP 里去了,可以让我们在PHP语言中使用,如standardReflectionCore 等。它们便是静态编译的,不是被编译成 so 或者 dll 文件供 PHP 动态调用,而是直接和 PHP 主程序编译到一起。

在 *nix 上执行静态编译

现在,先让我们执行一下 PHP 源码根目录下的 ./configure --help 命令。会发现输出信息并没有包含我们的扩展,这是因为这个 configure 脚本生成的时候,我们的扩展还没有编写呢。(这个configure是PHP官方分发的),所以首先我们需要使用 buildconf 命令生成新的 configure 脚本:

$ ./buildconf --force

现在当我们再执行 ./configure --help 的时候,便会发现 academy 扩展的信息已经出现了。现在我们只需要重新走一遍 PHP 的编译过程,便可以把我们的扩展以静态编译的方式加入到 PHP 主程序中了。千万不要忘记使用 --enable-academy 参数启用我们的扩展。

当然,对于我们学习如何开发 PHP 扩展来讲,静态编译可不是一个好主意,因为如果采用静态编译的方式,只要我们的扩展做了改动,便需要重新编译整个 PHP 才行,这个过程太痛苦了,还是用动态编译的方式吧,不过这种方式有利于提高性能,所以如果我们是在部署生产环境,则可以考虑。

学院君 has written 699 articles

资深PHP工程师,Laravel学院院长

One thought on “[ PHP 内核与扩展开发系列] 第一个 PHP 扩展:编译扩展

发表评论

标记为*的字段是必填项(邮箱地址不会被公开)

你可以使用这些HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>