PHP源码阅读点滴

下面讨论的PHP都是5.1.5版本的。

1. PHP源码文件 Zend/zend_globals.h 中的_zend_executor_globals定义了执行时全局的hash表:
    /* symbol table cache */
    HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
    HashTable **symtable_cache_limit;
    HashTable **symtable_cache_ptr;

    HashTable *active_symbol_table;
    HashTable symbol_table;     /* main symbol table */

    HashTable included_files;   /* files already included */
    HashTable *function_table;  /* function symbol table */
    HashTable *class_table;     /* class table */                    
    HashTable *zend_constants;  /* constants table */
    HashTable *in_autoload;

    HashTable regular_list;
    HashTable persistent_list;

    HashTable *ini_directives;

这里面只列了hash表类型的字段,从中可以看出: 函数、类、常量、头文件等都是存储为hash表的。

2. PHP源码文件 Zend/zend_globals.h 中的下列结构应该说明declare 关键字可以声明的内容都有哪些,似乎目前只有ticks

typedef struct _zend_declarables {
    zval ticks;
} zend_declarables;

3. hash表数据结构,Zend/zend_hash.h 文件中:

typedef struct _hashtable {
    uint nTableSize;
    uint nTableMask;
    uint nNumOfElements;
    ulong nNextFreeElement;
    Bucket *pInternalPointer;   /* Used for element traversal */
    Bucket *pListHead;
    Bucket *pListTail;
    Bucket **arBuckets;
    dtor_func_t pDestructor;
    zend_bool persistent;
    unsigned char nApplyCount;
    zend_bool bApplyProtection;
#if ZEND_DEBUG
    int inconsistent;
#endif
} HashTable;

4. PHP内部的Hash函数, Zend/zend_hash.h中:
static inline ulong zend_inline_hash_func(char *arKey, uint nKeyLength)
{
    register ulong hash = 5381;

    /* variant with the hash unrolled eight times */
    for (; nKeyLength >= 8; nKeyLength -= 8) {
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
    }
    switch (nKeyLength) {
        case 7: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough… */
        case 6: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough… */
        case 5: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough… */
        case 4: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough… */
        case 3: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough… */
        case 2: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough… */
        case 1: hash = ((hash << 5) + hash) + *arKey++; break;
        case 0: break;
EMPTY_SWITCH_DEFAULT_CASE()
    }
    return hash;
}

5. hash表查找函数:

/* Returns SUCCESS if found and FAILURE if not. The pointer to the
 * data is returned in pData. The reason is that there’s no reason
 * someone using the hash table might not want to have NULL data
 */
ZEND_API int zend_hash_find(HashTable *ht, char *arKey, uint nKeyLength, void **pData)
{
    ulong h;
    uint nIndex;
    Bucket *p;
       
    IS_CONSISTENT(ht);

    h = zend_inline_hash_func(arKey, nKeyLength);  
    nIndex = h & ht->nTableMask;
    p = ht->arBuckets[nIndex];
    while (p != NULL) { 
        if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
            if (!memcmp(p->arKey, arKey, nKeyLength)) {
                *pData = p->pData;
                return SUCCESS;
            }
        }
        p = p->pNext; 
    }        
    return FAILURE;
}    

这里面:    
    h = zend_inline_hash_func(arKey, nKeyLength);  
    nIndex = h & ht->nTableMask;
就可以定位到具体的
Bucket了,特别是这个按位与的操作,就可以知道Bucket的数量了,怎么算呢?

6. 文件Zend/zend_globals_macros.h中定义了EG:
# define EG(v) (executor_globals.v)

EG 就是executor_globals的意思,比如EG(ini_directives) 就是:
executor_globals.ini_directives

从上面的结构体executor_globals就可以知道这是在做什么了

7. Zend/zend_ini.h 中定义了ini变量的结构体:

struct _zend_ini_entry {
    int module_number;
    int modifiable;
    char *name;
    uint name_length;
    ZEND_INI_MH((*on_modify));
    void *mh_arg1;
    void *mh_arg2;
    void *mh_arg3;

    char *value;
    uint value_length;

    char *orig_value;
    uint orig_value_length;
    int modified;

    void (*displayer)(zend_ini_entry *ini_entry, int type);
};

8. ini_set 函数是在源码中是通过函数zend_alter_ini_entry来实现的,其中的modifytype参数值为:PHP_INI_USER

 

留下评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据