PHP 標準関数のソースを読んでみる

PHP Extensionの勉強をしよー!と言ったものの書き方を覚える前に、標準関数とかってどうやって書かれてるの?ってのが気になってきたので、PHP 5.2.2のソースを読んでみた。
しかし、まず何処に何のファイルが置かれていて、何処に何が書いているのかわからない!
数十分見回ってようやく、ext/standard の下あたりが面白そうだということを発見。

最初は手始めに簡単そうな処理を読みたいので、適当にstring.cを開き、
なんとな〜く目にとまった「strtoupper」を読んでみる。ぶら〜りソース読み旅。

なお、情報の正確さは保証しません。m(_ _)m

PHP_FUNCTION(strtoupper)

ext/standard/string.c

PHP_FUNCTION(strtoupper)
{
    zval **arg;
    
    if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg)) {
        WRONG_PARAM_COUNT;
    }
    convert_to_string_ex(arg);

    RETVAL_ZVAL(*arg, 1, 0);
    php_strtoupper(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));
}

PHP_FUNCTIONマクロ内に記述された名前がPHP上での関数名となる。
PHP_FUNCTIONについてはこちらのエントリーで詳しく解説してくれている。
おぎろぐはてな - PHP_FUNCTIONマクロ

関数内部でreturn_valueとか参照されているけどマクロ内に書かれているのね。
php上でreturnする値はreturn_valueに突っ込めばよさそう。

PHP_FUNCTION(strtoupper) の中

if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg)) {
    WRONG_PARAM_COUNT;
}

あたりでPHP上で渡された引数のチェックをして

convert_to_string_ex(arg);

PHPマニュアル

文字列への強制的な変換を行います。文字列が渡された場合は何もしません。 NULL 値は空の文字列に変換されます。Boolean TRUE は "1"、それ以外の Boolean は空の文字列となります。 long および double はそれぞれ対応する文字列表現に変換されます。 配列は "Array"、オブジェクトは "Object" という文字列に変換されます。

ということで引数を無理やり文字列にして*1

RETVAL_ZVAL(*arg, 1, 0);
// Zend/zend.h:
#define RETVAL_ZVAL(zv, copy, dtor)		ZVAL_ZVAL(return_value, zv, copy, dtor)
#define ZVAL_ZVAL(z, zv, copy, dtor) {  \
		int is_ref, refcount;           \
		is_ref = (z)->is_ref;           \
		refcount = (z)->refcount;       \
		*(z) = *(zv);                   \
		if (copy) {                     \
			zval_copy_ctor(z);          \
		}                               \
		if (dtor) {                     \
			if (!copy) {                \
				ZVAL_NULL(zv);          \
			}                           \
			zval_ptr_dtor(&zv);         \
		}                               \
		(z)->is_ref = is_ref;           \
		(z)->refcount = refcount;       \
	}

詳細は見てないけど、引数の文字列を戻り値にコピーして

php_strtoupper(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));

// Zend/zend_operators.h
#define Z_STRVAL_P(zval_p)		Z_STRVAL(*zval_p)
#define Z_STRLEN_P(zval_p)		Z_STRLEN(*zval_p)
#define Z_STRVAL(zval)			(zval).value.str.val
#define Z_STRLEN(zval)			(zval).value.str.len

文字列と長さを引数に、php_strtoupper()という関数を呼びだす。

*php_strtoupper

PHPAPI char *php_strtoupper(char *s, size_t len)
{
	unsigned char *c, *e;
	
	c = s;
	e = c+len;

	while (c < e) {
		*c = toupper(*c);
		c++;
	}
	return s;
}

内部の処理自体はあまりに普通なので何故か安心した…。

他にもいろいろ読んで少しずつ理解していこう。
今後もこの企画が続く。…かは知らない。

*1:echoった時とかにArrayと表示しやがるのはこいつのパワーか!