给PHP7.4编写扩展

给PHP7.4编写扩展

本文是以 PHP7.4 作为基础,讲解如何从零开始创建一个 PHP 扩展。本文主要讲解创建一个扩展的基本步骤都有哪些。示例中,我们将实现如下功能:

<?php

echo hello();

输出内容:

// $ php74 ./hello.php

$ hello word

在扩展中实现一个 hello 方法,调用 hello 方法后,输出 hello word!

生成扩展骨架

首先我们要有一份 php-src

git clone https://github.com/php/php-src.git 
cd php-src
git checkout PHP-7.4.5
cd php-7.4.10/ext
ls

可以看到有一个 ext_skel.php 文件

bcmath    com_dotnet  date  enchant       ffi       ftp      gmp    imap  ldap      mysqli   odbc     pcntl  pdo_dblib     pdo_oci    pdo_sqlite  posix     reflection  simplexml  soap     spl       sysvmsg  tidy       xmlreader  xsl        zlib
bz2       ctype       dba   exif          fileinfo  gd       hash   intl  libxml    mysqlnd  opcache  pcre   pdo_firebird  pdo_odbc   pgsql       pspell    session     skeleton   sockets  sqlite3   sysvsem  tokenizer  xmlrpc     zend_test
calendar  curl        dom   ext_skel.php  filter    gettext  iconv  json  mbstring  oci8     openssl  pdo    pdo_mysql     pdo_pgsql  phar        readline  shmop       snmp       sodium   standard  sysvshm  xml        xmlwriter  zip

这个已经文件已经跟 php 一起发布了,所以我们自定义起来非常方便

php ext_skel.php --ext hello --author aoppp --std

Copying config scripts... done
Copying sources... done
Copying tests... done

Success. The extension is now ready to be compiled. To do so, use the
following steps:

cd /path/to/php-src/hello
phpize
./configure
make

Don't forget to run tests once the compilation is done:
make test

Thank you for using PHP!

ext 目录下便生成 hello 目录

扩展骨架说明

-rw-r--r--   1 longshilin  staff   405 Feb 27 16:07 .gitignore
-rw-r--r--   1 longshilin  staff    11 Feb 27 16:07 CREDITS
-rw-r--r--   1 longshilin  staff  3231 Feb 27 16:07 config.m4
-rw-r--r--   1 longshilin  staff   204 Feb 27 16:07 config.w32
-rw-r--r--   1 longshilin  staff  3355 Feb 27 16:07 hello.c
-rw-r--r--   1 longshilin  staff  1425 Feb 27 16:07 php_hello.h
drwxr-xr-x   5 longshilin  staff   160 Feb 27 16:07 tests
  • config.m4配置文件

扩展的 config.m4 文件告诉 UNIX 构建系统哪些扩展 configure 选项是支持的,你需要哪些扩展库,以及哪些源文件要编译成它的一部分。对所有经常使用的 autoconf 宏,包括 PHP 特定的及 autoconf 内建的。

config.m4 的作用就是配合 phpize 工具生成 configure 文件。configure 文件是用于环境检测的。检测扩展编译运行所需的环境是否满足。现在我们开始修改 config.m4 文件。

-w1487

其中,dnl 是注释符号。

上面的代码说,如果你所编写的扩展如果依赖其它的扩展或者 lib 库,需要去掉 PHP_ARG_WITH 相关代码的注释。否则,去掉 PHP_ARG_ENABLE 相关代码段的注释。我们编写的扩展不需要依赖其他的扩展和 lib 库。因此,我们去掉 PHP_ARG_ENABLE 前面的注释。

上图生成的时候就已经指定是不依赖其他的扩展。

  • php_hello.h 头文件
    类似于C语言的头文件,包含了一些自定义的结构和函数声明,在这个demo中暂时不需要改动

  • hello.c代码文件

真正的逻辑代码都在这个文件中

编写代码

hello.c 里面都是逻辑代码,所以我们增加代码在这个文件中操作即可

了解扩展入口

整个扩展的入口是 zend_module_entry 这个结构,具体的定义可以在 Zend 目录下的zend_modules.h 文件中看到,一共有十几个属性,快速跳过,我们暂时只需要 hello

zend_module_entry hello_module_entry = {
	STANDARD_MODULE_HEADER,
	"hello",					/* Extension name */
	hello_functions,			/* zend_function_entry */
	NULL,							/* PHP_MINIT - Module initialization */
	NULL,							/* PHP_MSHUTDOWN - Module shutdown */
	PHP_RINIT(hello),			/* PHP_RINIT - Request initialization */
	NULL,							/* PHP_RSHUTDOWN - Request shutdown */
	PHP_MINFO(hello),			/* PHP_MINFO - Module info */
	PHP_HELLO_VERSION,		/* Version */
	STANDARD_MODULE_PROPERTIES
};

扩展相关属性说明:

  • STANDARD_MODULE_HEADER 帮我们实现了前面6个属性
  • hello 是扩展名称
  • hello_functions 是扩展包含的全部方法的集合,后面5个宏分别代表5个扩展特定方法
  • PHP_HELLO_VERSION 是扩展的版本号,定义在头文件中,如果需要修改的话直接打开php_hello.h 找到 define PHP_LZPAY_VERSION 进行修改
  • STANDARD_MODULE_PROPERTIES 帮我们实现了剩下的属性

hello_functions[] 方法数组中已经有了2个示例方法hello_test1hello_test2,我们参考它写我们的方法,首先我们写一个测试方法,放到函数 PHP_FUNCTION(hello_test2) 后面:

/*新增函数*/
PHP_FUNCTION(hello)
{
     zend_string *strg;
     strg = strpprintf(0, "hello word");
     RETURN_STR(strg);
}

然后在 hello_functions[] 数组中增加我们新写的函数

-w883

编译安装

因为我是新安装的一个独立的 php7.4,所以我的操作基本上都是带绝对路径的,如果大家就一个环境直接操作就行

cd hello/
/usr/local/Cellar/php/7.4.0/bin/phpize
./configure  --with-php-config=/usr/local/Cellar/php/7.4.0/bin/php-config
make && make install

----------------------------------------------------------------------------
Build complete.
Don't forget to run 'make test'.

Installing shared extensions:     /usr/local/Cellar/php/7.4.0/pecl/20190902/

安装好了,我们配置一下这个扩展

  • ext-hello.ini
[hello]
extension="/usr/local/Cellar/php/7.4.0/pecl/20190902/hello.so"

测试

hello git:(PHP-7.4.5) $ /usr/local/Cellar/php/7.4.0/bin/php -m | grep hello
# 输出成功说明ok
hello

-w910

您的支持是对我最大的鼓励!

发表于: 作者:憧憬。
关注互联网以及分享全栈工作经验的原创个人博客和技术博客,热爱编程,极客精神
Github 新浪微博 SegmentFault 掘金专栏