php 源碼 分析

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文件中如下定義了:

<?php
<
st_in_scripting > " if " {
              
return T_IF ;
      
} </ st_in_scripting >

這樣.php文件中的if就會被翻譯成內置符號T_IF。’(單引號)被如下定義:

<?php
<
st_single_quote > [ ' ] {
            BEGIN(ST_IN_SCRIPTING);
            return
' / '' ;
      }
      </
st_single_quote >
?>

4. 複合符號例如最常見的變量命名$discuz_user, $submit 等。

<?php
<
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行:

T_IF ' ( ' expr ' ) ' {
            
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:

r_variable { $$ = $ 1 ; }
            |
expr_without_variable { $$ = $ 1 ; }
      ;

if 後面可以跟 elseif 語句及 else 語句。
從語法樹裏面我們看出 if () 後面是可以跟 : 的,這一般很少被使用吧。

6. 優先級和左右結合性
一般情況下.y文件中最先定義的操作符優先級相對低,並且可以使用%left、%right 進行描述左右結合性,例如:

<?php
%
left ' + ' ' - ' ' . '
      %
left ' * ' ' / ' ' % '
      %
right ' ! '

這說明’!'在 PHP 語法中是右結合的, ‘*’ ‘/’ ‘%’ ‘+’ ‘-’ ‘.’ 是左結合的,並且’!'的優先級更高
例如語法 !$a + $b 要先計算 !$a 在進行加法操作%left ‘,’ 被放在最上面定義,說明他的優先級最低,因爲我們知道’,'可以等同一個語句。

7. php.ini的解析

1. 如果規定數值正負?

<?php
<
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行

<?php
-- ./
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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章