Register PHP function for small knowledge and big knowledge

coldplay.xixi
Release: 2023-04-09 15:04:01
forward
2063 people have browsed it

Register PHP function for small knowledge and big knowledge

[Related learning recommendations:php programming(video)]

Registration and use of PHP functions

The main goal of PHP extensions is to register new PHP functions for users. PHP functions are very complex and it is difficult to fully understand them and Zend Mechanisms closely related to the engine, but fortunately we don't need this knowledge in this chapter because the PHP extension mechanism provides many ways to abstract such complexity.

Registering and using a new PHP function in an extension is a simple step. However, it is much more complex to deeply understand the overall situation. The first step in the zend_function chapter may be helpful.

Obviously, you need to master types, especially zendValues and memory management. Of course, know your hooks.

zend_function_entry structure

Do not be confused with the zend_function structure,zend_function_entryis used in extensions to register functions for the engine. Look here:

#define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value typedef struct _zend_function_entry { const char *fname; void (*handler)(INTERNAL_FUNCTION_PARAMETERS); const struct _zend_internal_arg_info *arg_info; uint32_t num_args; uint32_t flags; } zend_function_entry;
Copy after login

You will see that the structure is not complicated, this is all needed to declare and register new functions. Let’s introduce it in detail:

The name of the function:fname. Nothing much to add, you know what it's for right? Just note that it isconst char *type. This does not apply to engines. Thisfnameis a model that the engine will create from the internal zend_string.

Then look athandler. This is a function pointer to the C code that will be the body of the function. Here, we'll use macros to simplify its declaration (as we'll see in a moment). Entering this function, we can parse the parameters the function receives and generate a return value, just like any PHP userland function. Note that this return value is passed as a parameter to our handler.

debate.arg_infoVariables are about declaring the API arguments that our function will receive. Again, this part can be difficult to understand in depth, but we don't need to understand it too deeply. We are again using macros to abstract and simplify parameter declarations. What you need to know is that you don't need to declare any parameters here to use the function, but we strongly recommend that you do so. We'll come back here. The argument is an array ofarg_info, so its size is passed asnum_args.

Thenflags. We will not elaborate on it in this chapter. These are used internally, you can learn more about them in the zend_function section.

Register PHP function

When the extension is loaded, the PHP function will be registered in the ZEND engine. An extension can declare a function vector in the extension structure. Functions declared by the extension are calledCorefunctions, as opposed toUserfunctions (functions declared and used in PHP users), they are not called at the end of the current request. Logout: can be used forever.

As a reminder, the following is an abbreviation for PHP extension structures for readability

struct _zend_module_entry { unsigned short size; unsigned int zend_api; unsigned char zend_debug; unsigned char zts; const struct _zend_ini_entry *ini_entry; const struct _zend_module_dep *deps; const char *name; const struct _zend_function_entry *functions; /* 函数声明向量 */ int (*module_startup_func)(INIT_FUNC_ARGS); int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); /* ... */ };
Copy after login

You will pass a declared function vector to the function vector. Let's look at a simple example:

/* pib.c 头文件*/ PHP_FUNCTION(fahrenheit_to_celsius) { } static const zend_function_entry pib_functions[] = { PHP_FE(fahrenheit_to_celsius, NULL) }; zend_module_entry pib_module_entry = { STANDARD_MODULE_HEADER, "pib", pib_functions, NULL, NULL, NULL, NULL, NULL, "0.1", STANDARD_MODULE_PROPERTIES };
Copy after login

Let's try a simple functionfahrenheit_to_celsius()(The name tells us what it does)

Pass Use thePHP_FUNCTION()macro to define a function. The latter will pass its arguments and expand into the correct structure. We then aggregate the function symbols and add them to thepib_functionsvector. This is thezend_function_entry *type extended by thezend_module_entrysymbol. In this vector, we add our PHP functions via thePHP_FEmacro. The latter requires the PHP function name, and a vector of arguments if we pass NULL values.

In thephp_pib.hheader file, we should declare our functions here just like in C language:

/* pib.h 头文件*/ PHP_FUNCTION(fahrenheit_to_celsius);
Copy after login

As you can see, declaring functions is really easy . Hong did all the hard work for us. Here's the same code as above, but with the macros expanded so you can see how they work:

/* pib.c */ void zif_fahrenheit_to_celsius(zend_execute_data *execute_data, zval *return_value) { } static const zend_function_entry pib_functions[] = { { "fahrenheit_to_celsius", zif_fahrenheit_to_celsius, ((void *)0), (uint32_t) (sizeof(((void *)0))/sizeof(struct _zend_internal_arg_info)-1), 0 }, }
Copy after login

Note howPHP_FUNCTION()ends withThe beginning of zif_is expanded to C symbol.'zif'is added to your function names to prevent PHP and its modules from causing symbol name conflicts during compilation. Therefore, ourfahrenheit_to_celsius()PHP function uses the handler ofzif_fahrenheit_to_celsius(). It's like almost every PHP function. If you searchzif_var_dump, you can read the source code functions of PHPvar_dump(), etc.

Declaring Function Parameters

So far, if "you compile" the extension and load it into PHP, you can see the reflection mechanism of the function rendering:

> ~/php/bin/php -dextension=pib.so --re pib Extension [  extension #37 pib version 0.1 ] { - Functions { Function [  function fahrenheit_to_celsius ] { } }
Copy after login

But It's missing parameters. If we issue afahrenheit_to_celsius($fahrenheit)function signature, a mandatory parameter is required.

你必须了解,函数声明和函数内部的运行无关。这意味着即便没有声明参数,我们现在编写函数也可能会起作用。

注意

声明参数虽然不是强制性的,但是我们强烈推荐使用。反射 API 可通过使用参数获取函数的信息。Zend 引擎也用到参数,尤其是当我们谈及引用传参或者返回引用的函数时。

要声明参数,我们必须要熟悉zend_internal_arg_info结构:

typedef struct _zend_internal_arg_info { const char *name; const char *class_name; zend_uchar type_hint; zend_uchar pass_by_reference; zend_bool allow_null; zend_bool is_variadic; } zend_internal_arg_info;
Copy after login

没必要详细说明每个字段,但是想要理解参数却比这种单独结构复杂得多。幸运的是,我们再次为你提供了一些宏来抽象这艰巨的工作。

ZEND_BEGIN_ARG_INFO_EX(arginfo_fahrenheit_to_celsius, 0, 0, 1) ZEND_ARG_INFO(0, fahrenheit) ZEND_END_ARG_INFO()
Copy after login

上面的代码详细的说明了如何创建参数,但当我们扩展宏时,我们会感到有些困难:

static const zend_internal_arg_info arginfo_fahrenheit_to_celsius[] = { { (const char*)(zend_uintptr_t)(1), ((void *)0), 0, 0, 0, 0 }, { "fahrenheit", ((void *)0), 0, 0, 0, 0 }, };
Copy after login

正如我们所见,宏创建了一个zend_internal_arg_info结构。如果你阅读过这类宏的 API,那么对我们来说一切都变得清楚了:

/* API only */ #define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) #define ZEND_ARG_INFO(pass_by_ref, name) #define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) #define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) #define ZEND_ARG_CALLABLE_INFO(pass_by_ref, name, allow_null) #define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) #define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name)
Copy after login

这一系列的宏可以让你处理每个用例。
This bunch of macros allow you to deal with every use-case.

  • ZEND_BEGIN_ARG_INFO_EX()允许你声明你的函数能接收多少个必要参数。它还允许你声明一个&return_by_ref()函数。
  • 那么你每个参数都需要ZEND_ARG_***_INFO()之一。使用它你可以判断参数是否为&$passed_by_ref以及是否需要类型提示。

注意

如果你不知道怎样去命名参数向量符号,则一种做法是使用‘arginfo_[function name]’模式。

所以回到我们的fahrenheit_to_celsius()函数,我们这里申明一个简单的按值返回函数(非常经典的用例),其中一个参数称为fahrenheit,且未通过引用传递(又一次的传统用例)。

这就创建了类型zend_internal_arg_info[](一个向量, 或一个数组, 都相同) 的arginfo_fahrenheit_to_celsius符号,现在我们必须要使用该符号回到函数声明中来添加给它一些参数。

PHP_FE(fahrenheit_to_celsius, arginfo_fahrenheit_to_celsius)
Copy after login

至此我们完成了,现在反射可以看见参数了,并会告知引擎在引用不匹配的情况下该怎么做。太棒了!

注意

还有其他宏。ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX()f.e. 你可以在 Zend/zend_api.h 的源代码中找到所有这些文件。

C 语言的 PHP 函数结构和 API

好的。下面是一个 PHP 函数。你可以使用它,并用 PHP 语言声明它(用户区):

function fahrenheit_to_celsius($fahrenheit) { return 5/9 * ($fahrenheit - 32); }
Copy after login

这是一个简单的函数,以便你可以理解它。这是用 C 编程时的样子:

PHP_FUNCTION(fahrenheit_to_celsius) { /* code to go here */ }
Copy after login

宏展开后,将得到:

void zif_fahrenheit_to_celsius(zend_execute_data *execute_data, zval *return_value) { /* code to go here */ }
Copy after login

休息一下,考虑一下主要差异。

首先奇怪的是,在 C 中,该函数不会返回任何东西。那是一个void声明的函数,你不可以在这里返回任何东西。但是我们注意到我们接收了一个zval *类型的return_value参数,看起来很不错。用 C 编写 PHP 函数时,你将得到一个指向 zval 的返回值 ,希望你们能玩一玩。这有更多关于 zval 的资源.

注意

在 C 扩展中编写 PHP 函数时,你接收作为参数的返回值,并且你不会从 C 函数返回任何东西。

好的,第一点解释了。第二点你可能已经猜到了:PHP 函数的参数在哪里?$fahreinheit在哪里?很难解释完全,事实上,这很难。

但是我们不需要在这里了解细节。让我们解释下关键的概念:

  • 参数已经通过引擎推入堆栈中。它们都在内存的某个地方挨着堆放。
  • 如果你的函数被调用,这意味着没有阻塞错误,因此你可以浏览参数堆栈,并读取运行时传递的参数。不仅是你声明的那些,还包括那些在调用函数时传递给函数的。引擎会为你处理一切。
  • 为了读取参数,你需要一个函数或者宏,并且需要知道有多少参数已经推入堆栈中,以便知道什么时候应该停止读取它们。
  • 一切都按照你接收的作为参数的zend_execute_data *execute_data。但是现在我们不详细说明。

解析参数:zend_parse_parameters()

要读取参数,欢迎使用zend_parse_parameters()API (称为 ‘zpp’).

注意

当在 C 扩展中编写 PHP 函数时,多亏了zend_parse_parameters()函数和它的朋友,你接收到 PHP 函数的参数。

zend_parse_parameters()是一个函数,它将为你到 Zend 引擎的堆栈中读取参数。你要告诉它要读取多少个参数,以及想要它为你提供哪种类型。该函数将根据 PHP 类型转换规则(如果需要,并且有可能的话)将参数转换为你要的类型。如果你需要一个整型,但给了一个浮点型,如果没有严格的类型提示规则被阻塞,则引擎会将浮点型转换为整型,然后给你。

让我们来看看这个函数:

PHP_FUNCTION(fahrenheit_to_celsius) { double f; if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &f) == FAILURE) { return; } /* continue */ }
Copy after login

我们希望在 f 变量上得到一个 double 类型。然后我们调用zend_parse_parameters()

第一个参数是运行时已给定的参数数目。ZEND_NUM_ARGS()是一个宏,它会告诉我们,然后我们用它去告知 zpp() 需要读取多少个参数。

然后我们传递一个const char *类型的“d”字符串。在这里,要求你为每一个接收的参数写一个字母,除了一些未在这里讲述的特殊情况。一个简单的“d”表示“如果需要的话,我想要第一个接收的参数转换为 float (double)”

然后,在该字符串之后传递 C 真正需要的参数,以满足第二个参数。一个“d”表示 “一个 double”,然后你现在传递 double 的地址,引擎将会填充其值。

注意

你总是将一个指针传递给要填充的数据。

你可以在 PHP 源代码的 README.PARAMETER_PARSING_API文件中找到关于 zpp() 的字符串格式的最新帮助。仔细阅读,因为这是你可能搞错并造成程序崩溃的一步。始终检查你的参数,始终根据你提供的格式字符串传递相同数量的参数变量,以及你要求的类型相同。要合乎逻辑。

同样注意一下参数解析的正常过程。zend_parse_parameters()函数在成功时应返回SUCCESS或者在失败时应返回FAILURE。失败可能表示你没有使用ZEND_NUM_ARGS()值,而是手动提供一个值(坏主意)。或者在参数解析时做错了什么。如果是这样,那么是时候 return 了,终止当前函数(你应该从 C 函数中返回void,所以只要return)。

到目前为止,我们接收了一个 double。让我们执行数学运算并返回结果:

static double php_fahrenheit_to_celsius(double f) { return ((double)5/9) * (double)(f - 32); } PHP_FUNCTION(fahrenheit_to_celsius) { double f; if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &f) == FAILURE) { return; } RETURN_DOUBLE(php_fahrenheit_to_celsius(f)); }
Copy after login

如你所知的zval 的工作原理,返回值对你来说应该很容易。你必须填写return_value

一些RETURN_***()宏以及一些RETVAL_***()宏都是专门用来这么做的。这两个仅设置return_valuezval 的类型和值,但是RETURN_***()宏后面会跟着一个从当前函数返回的 Creturn

或者,API 提供了一系列去处理和解析参数的宏。如果你对 python 样式说明符困惑的话,那么它更具有可读性。

你需要使用以下宏来开始和结束函数参数解析:

ZEND_PARSE_PARAMETERS_START(min_argument_count, max_argument_count) /* 需要两个参数 */ /* 这里我们将使用参数列表 */ ZEND_PARSE_PARAMETERS_END();
Copy after login

可用的参数宏可以列出如下:

Z_PARAM_ARRAY() /* old "a" */ Z_PARAM_ARRAY_OR_OBJECT() /* old "A" */ Z_PARAM_BOOL() /* old "b" */ Z_PARAM_CLASS() /* old "C" */ Z_PARAM_DOUBLE() /* old "d" */ Z_PARAM_FUNC() /* old "f" */ Z_PARAM_ARRAY_HT() /* old "h" */ Z_PARAM_ARRAY_OR_OBJECT_HT() /* old "H" */ Z_PARAM_LONG() /* old "l" */ Z_PARAM_STRICT_LONG() /* old "L" */ Z_PARAM_OBJECT() /* old "o" */ Z_PARAM_OBJECT_OF_CLASS() /* old "O" */ Z_PARAM_PATH() /* old "p" */ Z_PARAM_PATH_STR() /* old "P" */ Z_PARAM_RESOURCE() /* old "r" */ Z_PARAM_STRING() /* old "s" */ Z_PARAM_STR() /* old "S" */ Z_PARAM_ZVAL() /* old "z" */ Z_PARAM_VARIADIC() /* old "+" and "*" */
Copy after login

为了添加一个参数作为可选参数,我们使用以下宏:

Z_PARAM_OPTIONAL /* old "|" */
Copy after login

这是基于宏的参数解析样式的示例:

PHP_FUNCTION(fahrenheit_to_celsius) { double f; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_DOUBLE(f); ZEND_PARSE_PARAMETERS_END(); RETURN_DOUBLE(php_fahrenheit_to_celsius(f)); }
Copy after login

添加测试

如果你已阅读有关测试的章节(看使用 .phpt 文件测试),现在你应该编写一个简单的例子:

--TEST-- Test fahrenheit_to_celsius --SKIPIF--  --FILE--  --EXPECTF-- 21.11
Copy after login

并启动make test

玩转常量

让我们来看一个高级的例子。我们来添加相反的函数:celsius_to_fahrenheit($celsius):

ZEND_BEGIN_ARG_INFO_EX(arginfo_celsius_to_fahrenheit, 0, 0, 1) ZEND_ARG_INFO(0, celsius) ZEND_END_ARG_INFO(); static double php_celsius_to_fahrenheit(double c) { return (((double)9/5) * c) + 32 ; } PHP_FUNCTION(celsius_to_fahrenheit) { double c; if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &c) == FAILURE) { return; } RETURN_DOUBLE(php_celsius_to_fahrenheit(c)); } static const zend_function_entry pib_functions[] = { PHP_FE(fahrenheit_to_celsius, arginfo_fahrenheit_to_celsius) /* Done above */ PHP_FE(celsius_to_fahrenheit,arginfo_celsius_to_fahrenheit) /* just added */ PHP_FE_END };
Copy after login

现在是一个更复杂的用例,在将它作为 C 扩展实现之前,在 PHP 中展示它:

const TEMP_CONVERTER_TO_CELSIUS = 1; const TEMP_CONVERTER_TO_FAHREINHEIT = 2; function temperature_converter($temp, $type = TEMP_CONVERTER_TO_CELSIUS) { switch ($type) { case TEMP_CONVERTER_TO_CELSIUS: return sprintf("%.2f degrees fahrenheit gives %.2f degrees celsius", $temp, fahrenheit_to_celsius($temp)); case TEMP_CONVERTER_TO_FAHREINHEIT: return sprintf("%.2f degrees celsius gives %.2f degrees fahrenheit, $temp, celsius_to_fahrenheit($temp)); default: trigger_error("Invalid mode provided, accepted values are 1 or 2", E_USER_WARNING); break; } }
Copy after login

这个例子有助于我们介绍常量

常量在扩展中很容易管理,就像它们在用户区一样。常量通常是持久性的,意味着它们应该在请求之间保持其值不变。如果你知道 PHP 的生命周期,则应该猜到MINIT()是向引擎注册常量的正确阶段。

在内部,这有个常量,一个zend_constant结构:

typedef struct _zend_constant { zval value; zend_string *name; int flags; int module_number; } zend_constant;
Copy after login

真的是一个简单的结构(如果你深入了解常量是如何管理到引擎中,那可能会是一场噩梦)。你声明了namevalue,一些flags(不是很多),并且module_number自动设置为你的扩展编号(不用注意它)。

要注册常量,同样的,这一点都不难,一堆宏可以帮你完成:

#define TEMP_CONVERTER_TO_FAHRENHEIT 2 #define TEMP_CONVERTER_TO_CELSIUS 1 PHP_MINIT_FUNCTION(pib) { REGISTER_LONG_CONSTANT("TEMP_CONVERTER_TO_CELSIUS", TEMP_CONVERTER_TO_CELSIUS, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("TEMP_CONVERTER_TO_FAHRENHEIT", TEMP_CONVERTER_TO_FAHRENHEIT, CONST_CS|CONST_PERSISTENT); return SUCCESS; }
Copy after login

注意

给出 C 宏的 PHP 常量值是一个很好的实践。事情变得容易了,这就是我们做的。

根据你的常量类型,你将使用REGISTER_LONG_CONSTANT()REGISTER_DOUBLE_CONSTANT()等等。API 和宏位于 Zend/zend_constants.h中。

flag 在CONST_CS(case-sensitive constant 大小写敏感常量,我们想要的)和CONST_PERSISTENT(持久性常量,在请求中也是我们想要的)之间是混合的OR操作。

现在在 C 中的temperature_converter($temp, $type = TEMP_CONVERTER_TO_CELSIUS)函数:

ZEND_BEGIN_ARG_INFO_EX(arginfo_temperature_converter, 0, 0, 1) ZEND_ARG_INFO(0, temperature) ZEND_ARG_INFO(0, mode) ZEND_END_ARG_INFO();
Copy after login

我们得到了一个必须的参数,两个中的一个。那就是我们声明的。其默认值不是一个参数声明可以解决的,那将在一秒钟内完成。

然后我们将我们的新函数添加到函数注册向量:

static const zend_function_entry pib_functions[] = { PHP_FE(fahrenheit_to_celsius,arginfo_fahrenheit_to_celsius) /* seen above */ PHP_FE(celsius_to_fahrenheit,arginfo_celsius_to_fahrenheit) /* seen above */ PHP_FE(temperature_converter, arginfo_temperature_converter) /* our new function */ }
Copy after login

函数主体:

PHP_FUNCTION(temperature_converter) { double t; zend_long mode = TEMP_CONVERTER_TO_CELSIUS; zend_string *result; if (zend_parse_parameters(ZEND_NUM_ARGS(), "d|l", &t, &mode) == FAILURE) { return; } switch (mode) { case TEMP_CONVERTER_TO_CELSIUS: result = strpprintf(0, "%.2f degrees fahrenheit gives %.2f degrees celsius", t, php_fahrenheit_to_celsius(t)); RETURN_STR(result); case TEMP_CONVERTER_TO_FAHRENHEIT: result = strpprintf(0, "%.2f degrees celsius gives %.2f degrees fahrenheit", t, php_celsius_to_fahrenheit(t)); RETURN_STR(result); default: php_error(E_WARNING, "Invalid mode provided, accepted values are 1 or 2"); } }
Copy after login

记得好好看 README.PARAMETER_PARSING_API。它不是一个很难的 API,你必须熟悉它。

我们使用“d|l”作为zend_parse_parameters()的参数。一个 double、或(管道“|”)、一个 long。注意,如果在运行时不提供可选参数(提醒一下,ZEND_NUM_ARGS()是什么),则&mode不会被 zpp() 触及。这就是为什么我们提供了一个TEMP_CONVERTER_TO_CELSIUS默认值给该变量。

然后我们使用strpprintf()去构建一个 zend_string,并且使用RETURN_STR()返回它到return_valuezval。

注意

strpprintf()和它的朋友们在打印函数章节有解释过。

使用 Hashtable (PHP 数组)

现在让我们来玩一下PHP 数组并设计:

function multiple_fahrenheit_to_celsius(array $temperatures) { foreach ($temperatures as $temp) { $return[] = fahreinheit_to_celsius($temp); } return $return; }
Copy after login

所以在 C 语言实现的时候,我们需要zend_parse_parameters()并请求一个数组,遍历它,进行数学运算,并将结果作为数组添加到return_value

ZEND_BEGIN_ARG_INFO_EX(arginfo_multiple_fahrenheit_to_celsius, 0, 0, 1) ZEND_ARG_ARRAY_INFO(0, temperatures, 0) ZEND_END_ARG_INFO(); static const zend_function_entry pib_functions[] = { /* ... */ PHP_FE(multiple_fahrenheit_to_celsius, arginfo_multiple_fahrenheit_to_celsius) PHP_FE_END }; PHP_FUNCTION(multiple_fahrenheit_to_celsius) { HashTable *temperatures; zval *data; if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &temperatures) == FAILURE) { return; } if (zend_hash_num_elements(temperatures) == 0) { return; } array_init_size(return_value, zend_hash_num_elements(temperatures)); ZEND_HASH_FOREACH_VAL(temperatures, data) zval dup; ZVAL_COPY_VALUE(&dup, data); convert_to_double(&dup); add_next_index_double(return_value, php_fahrenheit_to_celsius(Z_DVAL(dup))); ZEND_HASH_FOREACH_END(); }
Copy after login

注意

你需要知道 Hashtable 的工作原理,并且必读 zval 章节

在这里,C 语言那部分将更快,因为不需要在 C 循环中调用 PHP 函数,但是一个静态(可能由编辑器内联的)函数,它的运行速度快了几个数量级,并且运行低级 CPU 指令所需的时间也更少。这并不是说这个小小的演示函数在代码性能方面需要如此多的关注,只要记住为什么我们有时会使用 C 语言代替 PHP。

管理引用

现在让我们开始玩 PHP 引用。您已经从 zval 章节 了解到引用是在引擎中使用的一种特殊技巧。作为提醒,引用(我们指的是&$php_reference)是分配给zval的,存储在zval的容器中。

所以,只要记住引用是什么以及它们的设计目的,就不难将它们处理成 PHP 函数。

如果你的函数接受一个参数作为引用,你必须在参数签名中声明,并从你的zend_parse_parameter()调用中传递一个引用。

让我们像往常一样,首先使用 PHP 示例:因此,现在C中,首先我们必须更改arg_info

ZEND_BEGIN_ARG_INFO_EX(arginfo_fahrenheit_to_celsius, 0, 0, 1) ZEND_ARG_INFO(1, fahrenheit) ZEND_END_ARG_INFO();
Copy after login

" 1 ",中传递的ZEND_ARG_INFO()宏告诉引擎必须通过引用传递参数。

然后,当我们接收到参数时,我们使用z参数类型,以告诉我们希望将它作为一个zval给出。当我们向引擎提示它应该向我们传递一个引用这一事实时,我们将获得对该zval的引用,也就是它的类型为is_reference时,我们只需要解引用它(即获取存储到zval中的zval),并按原样修改它,因为引用的预期行为是您必须修改引用所携带的值:

PHP_FUNCTION(fahrenheit_to_celsius) { double result; zval *param; if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", ¶m) == FAILURE) { return; } ZVAL_DEREF(param); convert_to_double(param); ZVAL_DOUBLE(param, php_fahrenheit_to_celsius(Z_DVAL_P(param))); }
Copy after login

完成。

注意

默认return_value值为NULL。如果我们不碰它,函数将返回PHP的NULL


想了解更多编程学习,敬请关注php培训栏目!

The above is the detailed content of Register PHP function for small knowledge and big knowledge. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:learnku.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!