介绍
在 PHP 中,模块是可扩展性的核心。一个模块可以增强或者修改 PHP 的行为,并将其编译为静态或者动态共享库。本文将介绍如何编写可扩展的模块,以及一些技巧来确保模块的稳定性和高效性。
1. 编写模块
模块结构
一个典型的 PHP 模块通常包括以下文件:
- php_xxx.h:定义模块的数据结构和函数原型声明。
- xxx.c:实现模块的功能代码。
- config.m4:关于模块编译的 Makefile 和配置文件。
下面是一个简单的例子。
// 文件:php_hello.h
#ifndef PHP_HELLO_H
#define PHP_HELLO_H
extern zend_module_entry hello_module_entry;
#define phpext_hello_ptr &hello_module_entry
#define PHP_HELLO_VERSION "1.0.0"
#ifdef PHP_WIN32
#
define PHP_HELLO_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
#
define PHP_HELLO_API __attribute__ ((visibility("default")))
#else
#
define PHP_HELLO_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
PHP_MINIT_FUNCTION(hello);
PHP_MSHUTDOWN_FUNCTION(hello);
PHP_RINIT_FUNCTION(hello);
PHP_RSHUTDOWN_FUNCTION(hello);
PHP_MINFO_FUNCTION(hello);
PHP_FUNCTION(hello_world);
#endif /* PHP_HELLO_H */
模块初始化
当编译完 PHP 模块后,需要将其加载到 PHP 运行时,以便 PHP 可以找到并使用这个模块。
在 PHP 模块加载时,会自动调用模块中的一个叫做 MINIT 的函数。这个函数会注册模块的函数和类。我们在这个函数中注册模块中的函数。
// 文件:hello.c
#include "php_hello.h"
static const zend_function_entry hello_functions[] = {
PHP_FE(hello_world, NULL)
PHP_FE_END
};
zend_module_entry hello_module_entry = {
STANDARD_MODULE_HEADER,
"hello",
hello_functions,
PHP_MINIT(hello),
PHP_MSHUTDOWN(hello),
PHP_RINIT(hello),
PHP_RSHUTDOWN(hello),
PHP_MINFO(hello),
PHP_HELLO_VERSION,
STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(hello);
PHP_FUNCTION(hello_world)
{
RETURN_STRING("Hello World", 1);
}
PHP_MINIT_FUNCTION(hello)
{
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(hello)
{
return SUCCESS;
}
PHP_RINIT_FUNCTION(hello)
{
return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(hello)
{
return SUCCESS;
}
PHP_MINFO_FUNCTION(hello)
{
php_info_print_table_start();
php_info_print_table_header(2, "hello support", "enabled");
php_info_print_table_end();
}
现在,我们需要将模块编译为动态共享库,可以使用 phpize 工具,生成 Makefile。
$ phpize
$ ./configure --enable-hello
$ make
检查是否生成了 hello.so 动态共享库。
$ ls modules/
hello.so
2. 扩展 PHP
在 PHP 中,C 语言扩展提供了几种添加功能的方法。
添加 PHP 函数
上面的例子中,通过 PHP_FUNCTION 宏定义了一个 "hello_world" 函数。这个函数可以在 PHP 中使用。
添加 PHP 类
一个 C 扩展可以向 PHP 中添加一个类,就像在 PHP 中定义类一样。在 C 扩展中添加的类与通过 PHP 实现的类相同,可以用来创建对象,调用方法,获取属性等。
修改 PHP 内核
C 扩展可以访问和修改 PHP 内核。PHP 提供了许多 API,可以让开发人员访问 PHP 内核中的各个部分,例如,zval 值,哈希表以及其他内部数据结构。
3. 扩展 Laravel
Laravel 是一个流行的 PHP Web 框架。Laravel 框架是开源的,越来越多的人将其作为 Web 开发的首选框架。在 Laravel 中,可以通过编写扩展来添加额外的功能。
有两种 Laravel 扩展类型:服务提供者和扩展包。
服务提供者
服务提供者是 Laravel 5 的核心组件之一。可以通过编写自定义服务提供者来扩展 Laravel 的功能。
服务提供者的主要目的是注册绑定到 Laravel 依赖注入器中的绑定,如:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class HelloServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('hello', function () {
return new \App\Services\HelloService();
});
}
}
扩展包
Laravel 扩展包是具有独立功能的单元,可以轻松地添加到 Laravel 项目中。
可以选择创建一个全新的 Laravel 扩展包,或者通过 composer 依赖项来管理已存在的 Laravel 扩展包。
下面是一个例子,展示了如何创建一个 Laravel 扩展包。
首先,使用 composer 创建一个新的项目:
$ composer create-project --prefer-dist laravel/laravel acme
$ cd acme/
接着,使用 Artisan 命令行工具来创建 Laravel 扩展包:
$ php artisan make:package acme/hello
生成了一个名为 hello 的包。在 packages/acme/hello 目录下新建了一个 ServiceProvider 类。
namespace Acme\Hello;
use Illuminate\Support\ServiceProvider;
class HelloServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('hello', function () {
return new Hello();
});
}
}
现在,只需将这个 ServiceProvider 放入主项目,然后添加
'providers' => [
// ...
Acme\Hello\HelloServiceProvider::class,
]
到主项目的 config/app.php 文件中即可。
总结
本文介绍了如何编写可扩展的 PHP 模块,使用 PHP 扩展来扩展 PHP 的各个方面,以及如何在 Laravel 框架中使用服务提供者和扩展包。编写可扩展的代码可以使您的代码更加灵活,易于维护并具有更高的可重用性。