PHP 4 (Zend Engine 1) 物件模型雖已淘汰,但理解其設計有助於掌握 PHP 5/7 物件演進脈絡。本文重建 sample2 擴展骨架,實作 PHP 4 風格類別定義、屬性與方法註冊流程。
$obj2 = $obj1 會**複製整個物件**(含屬性陣列)。__sleep/__wakeup)。zend_object 含 ce (類別項) + properties (HashTable)。php-src/ext/sample2/
├── config.m4
├── php_sample2.h
└── sample2.c
PHP_ARG_ENABLE(sample2, [Whether to enable the "sample2" extension],
[ --enable-sample2 Enable "sample2" extension support])
if test "$PHP_SAMPLE2" != "no"; then
PHP_SUBST(SAMPLE2_SHARED_LIBADD)
PHP_NEW_EXTENSION(sample2, sample2.c, $ext_shared)
fi
#ifndef PHP_SAMPLE2_H
#define PHP_SAMPLE2_H
#define PHP_SAMPLE2_EXTNAME "sample2"
#define PHP_SAMPLE2_EXTVER "1.0"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
extern zend_module_entry sample2_module_entry;
#define phpext_sample2_ptr &sample2_module_entry
#endif
#include "php_sample2.h"
static function_entry php_sample2_functions[] = {
{NULL, NULL, NULL}
};
PHP_MINIT_FUNCTION(sample2) {
return SUCCESS;
}
zend_module_entry sample2_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_SAMPLE2_EXTNAME,
php_sample2_functions,
PHP_MINIT(sample2),
NULL, NULL, NULL, NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_SAMPLE2_EXTVER,
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_SAMPLE2
ZEND_GET_MODULE(sample2)
#endif
cd php-src/ext/sample2
phpize
./configure --enable-sample2 --enable-debug --enable-maintainer-zts
make
make install
# php.ini 加入 extension=sample2.so
php -m | grep sample2
zend_class_entry *php_sample2_myclass_entry;
PHP_MINIT_FUNCTION(sample2) {
zend_class_entry ce;
// 1. 初始化類別項
INIT_CLASS_ENTRY(ce, "MyClass", php_sample2_myclass_functions);
// 2. 註冊內部類別,取得類別項指標
php_sample2_myclass_entry = zend_register_internal_class(&ce TSRMLS_CC);
// 3. (可選) 註冊預設屬性
zend_declare_property_long(php_sample2_myclass_entry, "counter", strlen("counter"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_string(php_sample2_myclass_entry, "name", strlen("name"), "", ZEND_ACC_PUBLIC TSRMLS_CC);
return SUCCESS;
}
// 方法表定義
static function_entry php_sample2_myclass_functions[] = {
PHP_FALIAS(myMethod, sample2_my_method, NULL)
{NULL, NULL, NULL}
};
// 方法實作 (PHP_FUNCTION 風格)
PHP_FUNCTION(sample2_my_method) {
zval *obj = getThis();
if (obj) {
// 存取屬性
zval **prop = zend_read_property(Z_OBJCE_P(obj), obj, "counter", strlen("counter"), 1 TSRMLS_CC);
long val = Z_LVAL_PP(prop);
Z_LVAL_PP(prop) = val + 1;
RETURN_LONG(val + 1);
}
RETURN_FALSE;
}
| 操作 | PHP 4 API | PHP 5+ API |
|---|---|---|
| 初始化類別項 | INIT_CLASS_ENTRY(ce, name, functions) | 同 |
| 註冊內部類別 | zend_register_internal_class(&ce) | 同 |
| 宣告屬性 | zend_declare_property_* | 同 |
| 定義方法 | PHP_FALIAS / PHP_FE | PHP_ME / PHP_METHOD |
| 取得 $this | getThis() | 同 |
| 讀取屬性 | zend_read_property() | zend_read_property() |
| 寫入屬性 | zend_update_property() | zend_update_property() |
// 使用者空間
$obj1 = new MyClass();
$obj1->counter = 5;
$obj2 = $obj1; // 複製:$obj2 獨立擁有 counter=5
$obj2->counter = 10;
echo $obj1->counter; // 輸出 5 (未受影響)
// 內部實作:object_init_ex() 建立新物件,複製 properties HashTable
zend_object_value.handle 作為唯一標識。EG(objects_store),而非直接內嵌於 zval。