メモ: マクロ PHP_FUNCTION を展開する

# 結論もどき

`PHP_FUNCTION(array_reverse)`
↓
`void zif_array_reverse(zend_execute_data *execute_data, zval *return_value)`

# 読むソースコード

[php/php-src: The PHP Interpreter](https://github.com/php/php-src)

手元のソースコードのコミットは [こちら](https://github.com/php/php-src/commit/18f2ef094af2b1ad961408fbaf222b9448df2750)

# `PHP_FUNCTION` が使われているところの例

```c:ext/standard/array.c
/* {{{ proto array array_reverse(array input [, bool preserve keys])
   Return input as a new array with the order of the entries reversed */
PHP_FUNCTION(array_reverse)
{
	zval	 *input,				/* Input array */
			 *entry;				/* An entry in the input array */
	zend_string *string_key;
	zend_ulong	  num_key;
	zend_bool preserve_keys = 0;	/* whether to preserve keys */

	ZEND_PARSE_PARAMETERS_START(1, 2)
		Z_PARAM_ARRAY(input)
		Z_PARAM_OPTIONAL
		Z_PARAM_BOOL(preserve_keys)
	ZEND_PARSE_PARAMETERS_END();

	/* Initialize return array */
	array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
	if ((HT_FLAGS(Z_ARRVAL_P(input)) & HASH_FLAG_PACKED) && !preserve_keys) {
		zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
		ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
			ZEND_HASH_REVERSE_FOREACH_VAL(Z_ARRVAL_P(input), entry) {
				if (UNEXPECTED(Z_ISREF_P(entry) &&
					Z_REFCOUNT_P(entry) == 1)) {
					entry = Z_REFVAL_P(entry);
				}
				Z_TRY_ADDREF_P(entry);
				ZEND_HASH_FILL_ADD(entry);
			} ZEND_HASH_FOREACH_END();
		} ZEND_HASH_FILL_END();
	} else {
		ZEND_HASH_REVERSE_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, string_key, entry) {
			if (string_key) {
				entry = zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, entry);
			} else {
				if (preserve_keys) {
					entry = zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, entry);
				} else {
					entry = zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), entry);
				}
			}
			zval_add_ref(entry);
		} ZEND_HASH_FOREACH_END();
	}
}
/* }}} */
```

# `PHP_FUNCTION` の定義はこちら

```c:main/php.h
#define PHP_FUNCTION			ZEND_FUNCTION
```

`PHP_FUNCTION(array_reverse)`
↓
`ZEND_FUNCTION(array_reverse)`

# `ZEND_FUNCTION` の定義はこちら

```c:Zend/zend_API.h
#define ZEND_FUNCTION(name)				ZEND_NAMED_FUNCTION(zif_##name)
```

`ZEND_FUNCTION(array_reverse)`
↓
`ZEND_NAMED_FUNCTION(zif_array_reverse)`

# `ZEND_NAMED_FUNCTION` の定義はこちら

```c:Zend/zend_API.h
#define ZEND_NAMED_FUNCTION(name)		void ZEND_FASTCALL name(INTERNAL_FUNCTION_PARAMETERS)
```

`ZEND_NAMED_FUNCTION(zif_array_reverse)`
↓
`void ZEND_FASTCALL zif_array_reverse(INTERNAL_FUNCTION_PARAMETERS)`

# `ZEND_FASTCALL` の定義はこちら

```c:Zend/zend_portability.h
#if defined(__GNUC__) && ZEND_GCC_VERSION >= 3004 && defined(__i386__)
# define ZEND_FASTCALL __attribute__((fastcall))
#elif defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER == 1700
# define ZEND_FASTCALL __fastcall
#elif defined(_MSC_VER) && _MSC_VER >= 1800 && !defined(__clang__)
# define ZEND_FASTCALL __vectorcall
#else
# define ZEND_FASTCALL
#endif
```

さっぱりわからないので `else` だと思い込むことにする。

`void ZEND_FASTCALL zif_array_reverse(INTERNAL_FUNCTION_PARAMETERS)`
↓
`void zif_array_reverse(INTERNAL_FUNCTION_PARAMETERS)`

# `INTERNAL_FUNCTION_PARAMETERS` の定義はこちら

```c:Zend/zend.h
#define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value
```

`void zif_array_reverse(INTERNAL_FUNCTION_PARAMETERS)`
↓
`void zif_array_reverse(zend_execute_data *execute_data, zval *return_value)`