PHP源代碼分析
1. 目錄結構
2. PHP使用Lex和Yacc對語法進行解析。
3. PHP如何使用Mysql?
4. 安全模式?
5. 那些是 PHP 的標準函數,那些是擴展函數?
6. PHP 源代碼中的PHP_FUNCTION(xx) 宏。
7. 那些函數集是標準的?
8. 一些函數的實現過程
9. PHP 函數集註冊過程
10. 有趣的Zend LOGO圖片
11. PHP的語法樹?
12. 從 CVS 獲取 PHP 源代碼
1. 目錄結構
1. build 和編譯有關的目錄。
2. ext 擴展庫代碼,例如 Mysql、zlib、iconv 等我們熟悉的擴展庫。
3. main 主目錄。
4. sapi 和各種服務器的接口調用,例如apache、IIS等,也包含一般的fastcgi、cgi等。
5. win32 和 Windows 下編譯 PHP 有關的腳本。用了 WSH。
6. Zend 文件夾核心的引擎。
7. scripts Linux 下的腳本目錄。
8. tests 測試腳本目錄
9. sapi 各類 Web 服務器的接口。
2. PHP使用Lex和Yacc對語法進行解析。
在 Zend 目錄下有兩個文件 zend_language_parser.y 與 zend_language_scanner.l
他們是Lex和Yacc的腳本文件,通過這兩個腳本文件生成對應的.c和.h文件,實際上這在 linux 下非常普遍,gcc 也使用它們產生語樹。
3. PHP如何使用Mysql?
ext 目錄下有一個 mysql 子目錄,這個目錄中的php_mysql.c 和 php_mysql.h 負責 PHP 與 Mysql 操作。使用了 Mysql 手冊中的 C 語言 API。
4. 安全模式?
main 文件夾下的safe_mode.h 和 safe_mode.c 文件負責PHP的安全模式。
5. 那些是 PHP 的標準函數,那些是擴展函數?
ext 目錄下英文意思是擴展,而在 ext 下還是有一個 standard 文件夾,存放着 PHP 中的標準函數,例如 explode 這個函數是在./ext/standard/string.c 下定義的。
6. PHP 源代碼中的PHP_FUNCTION(xx) 宏。
這個宏用來檢驗一個函數名稱是否合法。合法的函數名稱應該由小寫字母及下劃線組成。
7. 那些函數集是標準的?
通過 ./ext/standard/ 目錄我們可以看到以下常用函數集是標準的。字符串函數集、數組函數集、文件及目錄操作函數集、md5算法等。
8. 一些函數的實現過程
1. fsockopen, pfsockopen 的實現
這兩個函數的實現離不開 ./ext/standard/fsock.c 文件中的 php_fsockopen_stream 函數。具體的socket都在./main/network.c 中實
現。
9. PHP 函數集註冊過程
在./main/internal_functions.c 中有一個數組 php_builtin_extensions 默認下有以下成員:
1. phpext_bcmath_ptr
2. phpext_calendar_ptr
3. phpext_com_dotnet_ptr
4. phpext_ctype_ptr
5. phpext_date_ptr
6. phpext_ftp_ptr
7. phpext_hash_ptr
8. phpext_odbc_ptr
9. phpext_pcre_ptr
10. phpext_reflection_ptr
11. phpext_session_ptr
12. phpext_spl_ptr
13. phpext_standard_ptr
14. phpext_tokenizer_ptr
15. phpext_zlib_ptr
接着 php_register_extensions(php_builtin_extensions, EXTCOUNT TSRMLS_CC) 進行註冊
10. 有趣的Zend LOGO圖片
./main/logos.h 文件中,用 zend_logo 與 php_logo 數組保存了 PHP 標誌和 Zend 標誌。所以你根本在發行包裏找不到zend.gif。
11. PHP的語法樹?
1. Lex與Yacc
市面上有這本書。大家可以買來看看,包括GCC都是用它們兄弟生成的語法樹。如果對編譯器感興趣。可以翻閱市面上關於這方面的書,並不多就幾本。
2. y語法樹文件
./Zend/zend_language_scanner.l與./Zend/zend_language_parser.y
規定了PHP的語法。從字面意義上scanner表示語法初步掃描,
parser表示語法解析。根據這兩個文件lex與yacc可以生成對應的c代碼。所以相對來說生成語法是很方便的。
3. 如何定義一個符號
例如 if($language=’php’) 這一句中的if 就是一個token 語法中我們用T_IF表示。具體在.l文件中如下定義了:
< st_in_scripting > " if " {
return T_IF ;
} </ st_in_scripting >
這樣.php文件中的if就會被翻譯成內置符號T_IF。’(單引號)被如下定義:
< st_single_quote > [ ' ] {
BEGIN(ST_IN_SCRIPTING);
return ' / '' ;
}
</ st_single_quote >
?>
4. 複合符號例如最常見的變量命名$discuz_user, $submit 等。
< st_in_scripting , ST_DOUBLE_QUOTES , ST_HEREDOC , ST_BACKQUOTE > " $ " { LABEL } {
zend_copy_value ( zendlval , ( yytext + 1 ) , ( yyleng - 1 )) ;
zendlval -> type = IS_STRING ;
return T_VARIABLE ;
}
</ st_in_scripting >
5. 一個有效的if語句過程
這個定義在zend_language_parser.y 189行:
zend_do_if_cond ( &$ 3 , &$ 4 TSRMLS_CC ) ;
} statement {
zend_do_if_after_statement ( &$ 4 , 1 TSRMLS_CC ) ;
} elseif_list else_single {
zend_do_if_end ( TSRMLS_C ) ;
}
| T_IF ' ( ' expr ' ) ' ' : ' {
zend_do_if_cond ( &$ 3 , &$ 4 TSRMLS_CC ) ;
} inner_statement_list {
zend_do_if_after_statement ( &$ 4 , 1 TSRMLS_CC ) ;
} new_elseif_list new_else_single T_ENDIF ' ; ' {
zend_do_if_end ( TSRMLS_C ) ;
}
if 後面必須存在(),圓括弧裏面是表達式 expr 表達式在734行被定義:
expr:
| expr_without_variable { $$ = $ 1 ; }
;
if 後面可以跟 elseif 語句及 else 語句。
從語法樹裏面我們看出 if () 後面是可以跟 : 的,這一般很少被使用吧。
6. 優先級和左右結合性
一般情況下.y文件中最先定義的操作符優先級相對低,並且可以使用%left、%right 進行描述左右結合性,例如:
% left ' + ' ' - ' ' . '
% left ' * ' ' / ' ' % '
% right ' ! '
這說明’!'在 PHP 語法中是右結合的, ‘*’ ‘/’ ‘%’ ‘+’ ‘-’ ‘.’ 是左結合的,並且’!'的優先級更高
例如語法 !$a + $b 要先計算 !$a 在進行加法操作%left ‘,’ 被放在最上面定義,說明他的優先級最低,因爲我們知道’,'可以等同一個語句。
7. php.ini的解析
1. 如果規定數值正負?
< initial > [ ] * ( " true " | " on " | " yes " )[ ] * {
ini_lval -> value . str . val = zend_strndup ( " 1 " , 1 ) ;
ini_lval -> value . str . len = 1 ;
ini_lval -> type = IS_STRING ;
return CFG_TRUE ;
}
</ initial >< initial > [ ] * ( " false " | " off " | " no " | " none " )[ ] * {
ini_lval -> value . str . val = zend_strndup ( "" , 0 ) ;
ini_lval -> value . str . len = 0 ;
ini_lval -> type = IS_STRING ;
return CFG_FALSE ;
} </ initial >
12. 從 CVS 獲取 PHP 源代碼
1. 安裝 CVS 版本工具,例如 TortoiseCVS。
2. cvs -d :pserver:[email protected]:/repository checkout php-src 具體的CVS使用辦法請參考 CVS 手冊及其它著作。
PHP.ini 文件的默認配置,定義在 ./main/main.c 342行
-- ./ main / main . c -- 342 :
/* {{{ PHP_INI
*/
PHP_INI_BEGIN ()
PHP_INI_ENTRY_EX ( " define_syslog_variables " , " 0 " , PHP_INI_ALL , NULL ,
php_ini_boolean_displayer_cb )
PHP_INI_ENTRY_EX ( " highlight.bg " , HL_BG_COLOR , PHP_INI_ALL , NULL ,
php_ini_color_displayer_cb )
PHP_INI_ENTRY_EX ( " highlight.comment " , HL_COMMENT_COLOR , PHP_INI_ALL , NULL ,
php_ini_color_displayer_cb )
PHP_INI_ENTRY_EX ( " highlight.default " , HL_DEFAULT_COLOR , PHP_INI_ALL , NULL ,
php_ini_color_displayer_cb )
PHP_INI_ENTRY_EX ( " highlight.html " , HL_HTML_COLOR , PHP_INI_ALL , NULL ,
php_ini_color_displayer_cb )
PHP_INI_ENTRY_EX ( " highlight.keyword " , HL_KEYWORD_COLOR , PHP_INI_ALL , NULL ,
php_ini_color_displayer_cb )
PHP_INI_ENTRY_EX ( " highlight.string " , HL_STRING_COLOR , PHP_INI_ALL , NULL ,
php_ini_color_displayer_cb )
more lines ... ...
PHP_INI_END ()
/* }}} */
-- ./ main / main . c --
在最新版本的PHP中 memory_limit 由原來的 8M 修改成了 16M