有时候还是得逼自己一把,自从写了下玩具编译器后,就对语言底层原理产生了浓厚的兴趣。但是,C
语言本身呢,看起来似乎语言本身的内容不多,但真的太灵活了,一个宏就能让人晕头转向;还有各种贴近硬件的类型,未定义行为,指针,想写好真的不简单。PHP
解释器是用C
实现的,因此也容易让我产生畏难情绪。
其实学C
语言的时间也不短了,却一直没用它写过像样的程序。最近又翻了下一本C
语言书,有了些许收获,也许会让我能沉下心来钻进PHP
解释器中。同时,PHP
基金会的成立也让我对这门语言越来越有了接近之意,关注了很多社区中的大牛,也许受了感染吧,感觉就挺有意思。
最重要的就是想深入一门语言,探究其本质,对其它语言的使用也有帮助。语言不计其数,究其源头是相通的,不给自己限定为XX
语言的开发者,对语言少些敬畏,减少其带来的束缚。
下面直接点吧,先给PHP
加上自己想要的函数,就 https://github.com/phpinternalsbook/PHP-Internals-Book 书中简单的dump
函数以及自己加的helloworld
函数。
PHP
的库函数基本都位于ext
目录中,其中standard
又是最小化安装时仅剩的几个扩展之一,因此我决定将这两个函数放在这里,该目录中又以basic_functions.c
最得我心,就放这了,在ext/standard/basic_functions.c
末尾加上以下代码:
// ext/standard/basic_functions.c
PHP_FUNCTION(dump)
{
zval *zv_ptr;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zv_ptr) == FAILURE) {
return;
}
try_again:
switch (Z_TYPE_P(zv_ptr)) {
case IS_NULL:
php_printf("NULL: null\n");
break;
case IS_TRUE:
php_printf("BOOL: true\n");
break;
case IS_FALSE:
php_printf("BOOL: false\n");
break;
case IS_LONG:
php_printf("LONG: %ld\n", Z_LVAL_P(zv_ptr));
break;
case IS_DOUBLE:
php_printf("DOUBLE: %g\n", Z_DVAL_P(zv_ptr));
break;
case IS_STRING:
php_printf("STRING: value=\"");
PHPWRITE(Z_STRVAL_P(zv_ptr), Z_STRLEN_P(zv_ptr));
php_printf("\", length=%zd\n", Z_STRLEN_P(zv_ptr));
break;
case IS_RESOURCE:
php_printf("RESOURCE: id=%d\n", Z_RES_HANDLE_P(zv_ptr));
break;
case IS_ARRAY:
php_printf("ARRAY: hashtable=%p\n", Z_ARRVAL_P(zv_ptr));
break;
case IS_OBJECT:
php_printf("OBJECT: object=%p\n", Z_OBJ_P(zv_ptr));
break;
case IS_REFERENCE:
// For references, remove the reference wrapper and try again.
// Yes, you are allowed to use goto for this purpose!
php_printf("REFERENCE: ");
zv_ptr = Z_REFVAL_P(zv_ptr);
goto try_again;
EMPTY_SWITCH_DEFAULT_CASE() // Assert that all types are handled.
}
}
PHP_FUNCTION(helloworld)
{
printf("Hello world\n");
}
可以发现,想要给PHP
添加新函数,只需要用PHP_FUNCTION
宏包装一下即可。helloworld
最为简单,深得我心。目前PHP 8.2.6
除了定义函数外,还需要在ext/standard/basic_functions.stub.php
中加上函数原型
,姑且叫它函数原型吧,就看它像C
语言的函数原型。至于PHP 8.2.6
之前的版本先不管,再次在文件末尾加上以下代码:
// ext/standard/basic_functions.stub.php
function dump(mixed $value): void {}
function helloworld(): void {}
至此,我们的代码任务告一段落。假设之前已经手工配置编译安装了PHP
,现在只需要重新编译安装即可:
$ make && make install
此时,可以试验自己添加的功能了:
$ php -r 'dump("Hello world");helloworld();'
STRING: value="Hello world", length=11
Hello world
有点意思,顿时来了兴趣,希望以后能更深入地了解PHP
底层原理。