草庐IT

php - 如何使 ZEND_BEGIN_ARG_INFO_EX 控制传递给 PHP 扩展的参数数量?

coder 2024-01-05 原文

我正在使用 C 开发一个 PHP 扩展。到目前为止,我正在对从 PHP 用户空间传递给扩展函数的参数进行正确验证。

ZEND_BEGIN_ARG_INFO_EX 可用于为 Zend Engine 提供有关函数参数的信息。宏的第4个参数,命名为required_num_args,让引擎自动控制参数个数,省去了我这个麻烦。然而,我找不到让它工作的方法:引擎总是在没有任何警告的情况下运行扩展的功能,即使 PHP 脚本没有向那里传递足够的参数。

这是我对函数参数的定义:

ZEND_BEGIN_ARG_INFO_EX(test_func_swt_arginfo, 0, 0, 3)
    ZEND_ARG_INFO(1, firstArg)
    ZEND_ARG_ARRAY_INFO(0, secondArg, true)
    ZEND_ARG_OBJ_INFO(1, thirdArg, SomeClass, false)
ZEND_END_ARG_INFO()

这是我对函数的定义,由 PHP 扩展导出:

static const zend_function_entry test_func_functions[] = {
    PHP_FE(sample_with_types, test_func_swt_arginfo)
    PHP_FE_END
};

这是我的功能:

PHP_FUNCTION(sample_with_types)
{
    RETURN_TRUE;
}

这是我运行的 PHP 脚本:

<?php
sample_with_types();

预期结果:PHP 显示错误/警告/异常,类似“没有足够的参数传递给函数”;函数不执行。

实际结果:函数执行并返回true

如何正确配置函数参数结构,以便 Zend Engine 自动检查参数数量?还是我弄错了 ZEND_BEGIN_ARG_INFO_EX 宏中 required_num_args 参数的用途?

最佳答案

据我所知,这不是 ZEND_BEGIN_ARG_INFO_EX 的目的。

ZEND_BEGIN_ARG_INFO_EX 是 PHP 5 的新增功能,用于生成更简洁的代码,支持类型提示、按引用传递和反射。考虑以下仅返回 true 的实际函数的 arginfo 声明:

ZEND_BEGIN_ARG_INFO_EX(arginfo_test, 0, 0, 3)
    ZEND_ARG_INFO(0, firstArg)
    ZEND_ARG_OBJ_INFO(0, objNonNull, stdClass, 0)
    ZEND_ARG_OBJ_INFO(0, obj, stdClass, 1)
    ZEND_ARG_OBJ_INFO(1, objByRef, stdClass, 1)
ZEND_END_ARG_INFO()

效果如下:

sample_with_types();                          // ok
sample_with_types(1, null);                   // error: arg #2 should be stdClass
sample_with_types(1, new stdClass, null);     // ok
sample_with_types(1, new stdClass, 1);        // error: arg #3 should be stdClass
sample_with_types(1, new stdClass, null, 2);  // error: arg #4 must be reference

此外,它还为您的函数提供反射功能:

$ref = new ReflectionFunction('sample_with_types');
var_dump($ref->getParameters());

...给出类似的输出:

array(4) {
  [0]=>
  &object(ReflectionParameter)#2 (1) {
    ["name"]=>
    string(8) "firstArg"
  }
  [1]=>
  &object(ReflectionParameter)#3 (1) {
    ["name"]=>
    string(10) "objNonNull"
  }
  [2]=>
  &object(ReflectionParameter)#4 (1) {
    ["name"]=>
    string(3) "obj"
  }
  [3]=>
  &object(ReflectionParameter)#5 (1) {
    ["name"]=>
    string(8) "objByRef"
  }
}

如果省略 arginfo,ReflectionFunction::getParameters() 将返回一个空数组。

required_num_args 宏参数是专门用于反射的,表示在反射函数时标记多少个参数是必需的。

如果你需要使参数成为必需的,而不仅仅是在使用反射时将它们标记为必需的,你仍然必须使用zend_parse_parameters,在大多数情况下,你仍然需要获取实际值参数:

PHP_FUNCTION(sample_with_types)
{
    long arg1;
    zval *arg2 = NULL, *arg3 = NULL, *arg4 = NULL;
    zend_class_entry ce2, ce3, ce4;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "looo", &arg1, 
                              &arg2, &ce2, &arg3, &ce3, &arg4, &ce4) == FAILURE)
    {
        return;
    }

    RETURN_TRUE;
}

请注意我在上面是如何使用 "looo"(通用对象类型)而不是 "lOO!O!"(具有 null 说明符的特定对象类型)。类型提示已使用 arginfo 指定,因此无需执行两次。

所以,没有 arginfo:

  • 您必须使用少量的 zend_fetch_class 调用和类条目来类型提示您的对象参数。
  • 它不会启用反射。
  • 您将无法声明通过引用传递的参数。
  • 它显然会产生不太干净的代码。

出于显而易见的原因,您需要确保您的 arginfo 声明和您的 zend_parse_parameters 调用匹配。

关于php - 如何使 ZEND_BEGIN_ARG_INFO_EX 控制传递给 PHP 扩展的参数数量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14635111/

有关php - 如何使 ZEND_BEGIN_ARG_INFO_EX 控制传递给 PHP 扩展的参数数量?的更多相关文章

  1. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

  2. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

  3. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  4. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

    一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

  5. ruby - 如何将 Puma::Configuration 传递给 Sinatra? - 2

    这是我的网络应用:classFront我是这样开始的(请不要建议使用Rack):Front.start!这是我的Puma配置对象,我不知道如何传递给它:require'puma/configuration'Puma::Configuration.new({log_requests:true,debug:true})说真的,怎么样? 最佳答案 配置与您运行的方式紧密相关puma服务器。运行的标准方式puma-pumaCLI命令。为了配置puma配置文件config/puma.rb或config/puma/.rb应该提供(参见examp

  6. jquery - 如何将 AJAX 变量从 jQuery 传递到他们的 Controller ? - 2

    我有一个电子邮件表格。但是我正在制作一个测试电子邮件表单,用户可以在其中添加一个唯一的电子邮件,并让电子邮件测试将其发送到该特定电子邮件。为了简单起见,我决定让测试电子邮件通过ajax执行,并将整个内容粘贴到另一个电子邮件表单中。我不知道如何将变量从我的HAML发送到我的Controllernew.html.haml-form_tagadmin_email_blast_pathdoSubject%br=text_field_tag'subject',:class=>"mass_email_subject"%brBody%br=text_area_tag'message','',:nam

  7. ruby - 我怎样才能只写一次 "Text"并同时检查 path_info 是否包含 'A' ? - 2

    -if!request.path_info.include?'A'%{:id=>'A'}"Text"-else"Text"“文本”写了两次。我怎样才能只写一次并同时检查path_info是否包含“A”? 最佳答案 有两种方法可以做到这一点。使用部分,或使用content_forblock:如果“文本”较长,或者是一个重要的子树,您可以将其提取到一个部分。这会使您的代码变干一点。在给出的示例中,这似乎有点矫枉过正。在这种情况下更好的方法是使用content_forblock,如下所示:-if!request.path_info.inc

  8. ruby - 如何将 lambda 传递给 Hash.each? - 2

    如何将lambda传递给hash.each,以便我可以重复使用一些代码?>h={a:'b'}>h.eachdo|key,value|end=>{:a=>"b"}>test=lambdado|key,value|puts"#{key}=#{value}"end>test.call('a','b')a=b>h.each&testArgumentError:wrongnumberofarguments(1for2)from(irb):1:in`blockinirb_binding'from(irb):5:in`each'from(irb):5from/Users/jstillwell/.rv

  9. ruby - 将命令行上的变量传递给 Cucumber 测试 - 2

    我正在尝试将cucumber项目的用户名和密码置于版本控制之外。有没有办法在命令行上手动将用户名和密码等变量传递给Cucumber脚本?我的备份计划是将它们放在一个YML文件中,然后将该文件添加到gitignore,这样它们就不会被置于版本控制中。 最佳答案 所以,我看到了您对铁皮人的评论,答案是肯定的。cucumberPASSWORD=my_passwordPASSWORD被设置为环境变量,您可以通过将其引用为ENV['PASSWORD']来使用它的值。例如,browser.text_field(:id=>'pwd').setEN

  10. Ruby HERE-DOC方法参数传递 - 2

    我正在尝试将自定义方法与here-doc一起使用,并希望传递参数(没有业务案例,我只是想学习ruby​​)。在这种情况下有没有办法传递参数?这是我目前所拥有的。方法简单,效果很好。defmeth1self.upcaseendstr1=现在,我想让我们放弃一些参数并尝试不同的变体,irb给了我一个茫然的眼神。#variation1defmeth2( 最佳答案 我猜这就是您要尝试做的:defmeth2(str1,str2)str1.upcase+"..."+str2.downcaseendstr2=meth2("SOMESTRING\n

随机推荐