首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 4 物件模型詳解:從結構體到 zend_class_entry 註冊流程

     編輯:PHP 綜合知識

PHP 4 (Zend Engine 1) 物件模型雖已淘汰,但理解其設計有助於掌握 PHP 5/7 物件演進脈絡。本文重建 sample2 擴展骨架,實作 PHP 4 風格類別定義、屬性與方法註冊流程。

PHP 4 物件核心特徵

  • 物件本質 = **陣列 + 方法綁定**。「將一個陣列和一些方法綁定在一起」。
  • **傳值語意**:$obj2 = $obj1 會**複製整個物件**(含屬性陣列)。
  • 無可見性控制、無介面、無靜態成員、無魔術方法 (除 __sleep/__wakeup)。
  • 內部結構:zend_object 含 ce (類別項) + properties (HashTable)。

重建 sample2 擴展骨架

php-src/ext/sample2/
├── config.m4
├── php_sample2.h
└── sample2.c

config.m4

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

php_sample2.h

#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

sample2.c (最小骨架)

#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

PHP 4 類別定義流程 (MINIT 中)

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;
}

關鍵 API 對照

操作PHP 4 APIPHP 5+ API
初始化類別項INIT_CLASS_ENTRY(ce, name, functions)同
註冊內部類別zend_register_internal_class(&ce)同
宣告屬性zend_declare_property_*同
定義方法PHP_FALIAS / PHP_FEPHP_ME / PHP_METHOD
取得 $thisgetThis()同
讀取屬性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

從 PHP 4 到 PHP 5 的關鍵變革

  • 傳參語意:PHP 4 複製整個物件 → PHP 5 傳遞 handle (類似參考)。
  • 物件標識:PHP 5 引入 zend_object_value.handle 作為唯一標識。
  • 物件儲存:PHP 5 物件實例儲存在 EG(objects_store),而非直接內嵌於 zval。
  • 可見性/介面/靜態/魔術方法:PHP 5 全新支援。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved