Hello Dmitry,

  the 'f' requires at least the first helper, so it makes sense to have
all three of them in the engine. Attached you will find the patch for
the helpers and the 'f' thingie for 5.2 and an additional patch for SPL
to introduce iterator_apply() which uses the stuff.

marcus

Wednesday, May 31, 2006, 12:46:59 PM, you wrote:

> Hmm,

> Seems 'f' really make sense for simplification.
> I am not sure about other helpers.
> I'll need to review patch once again.
> Could you include some use-cases (SPL patch that uses this one)?

> Thanks. Dmitry.

>> -----Original Message-----
>> From: Marcus Boerger [mailto:[EMAIL PROTECTED] 
>> Sent: Wednesday, May 31, 2006 12:19 PM
>> To: Dmitry Stogov; internals@lists.php.net
>> Cc: [EMAIL PROTECTED]; 'Andi Gutmans'; Zeev Suraski
>> Subject: Re: MFHing zend_fcall_info_*() to 5.2
>> 
>> 
>> Hello Dmitry,
>> 
>>   my patch doesn't change anything. If just adds stuff that 
>> deals with defined functions only. If now you want to support 
>> all functions that can be defined later it wouldn't work this 
>> way (1). Actually it would require parsing the zval and 
>> checking whether it might get callable in some future. While 
>> this is the right solution for error handlers it is not the 
>> right way for stuff like callback in array and SPL functions. 
>> Once those are called the callback is used hence there is no 
>> way it can suddenly come out of nowhere. My patch now 
>> adresses this in a way that is much more efficient than doing 
>> a two phase approach.
>> 
>> best regards
>> marcus
>> 
>> (1) I experiemened with 'F' parsing that only verified if 
>> something might get callable at some point. Though that 
>> worked it was unneccessary slow for the intended purpose.
>> 
>> Wednesday, May 31, 2006, 8:29:01 AM, you wrote:
>> 
>> > Hi Marcus,
>> 
>> > We discussed the patch.
>> 
>> > Several notes:
>> > PHP allowed pass callback function or method that is not 
>> defined yet.
>> > Your patch disallows this.
>> 
>> > <?php
>> > some_internal_func("foo");
>> > eval("function foo() {}");
>> ?>>
>> 
>> > Usage of default values for functions will be problematic 
>> with it. I 
>> > don't think that we really need special case for 'callback' 
>> afguments. 
>> > (It would be good for strong-typed language).
>> 
>> > According to helpers, I would like suggest to add them into SPL  
>> > itself and don't overload ZE.
>> 
>> I can do so but don't see sense in doing so.
>> 
>> best regards
>> marcus
>> 
>> >> >Date: Sat, 27 May 2006 22:32:13 +0200
>> >> >From: Marcus Boerger <[EMAIL PROTECTED]>
>> >> >Reply-To: Marcus Boerger <[EMAIL PROTECTED]>
>> >> >To: Andi Gutmans <[EMAIL PROTECTED]>, Zeev Suraski <[EMAIL PROTECTED]>,
>> >> >         Ilia Alshanetsky <[EMAIL PROTECTED]>
>> >> >Cc: internals@lists.php.net
>> >> >Subject: MFHing zend_fcall_info_*() to 5.2
>> >> >X-Bogosity: No, tests=bogofilter, spamicity=0.000475, 
>> version=0.92.8
>> >> >
>> >> >Hello Andi, Zeev, Ilia,
>> >> >
>> >> >   the attached patch adds three new functions that make calling
>> >> >functions a lot easier - at least for me in SPL. And it also 
>> >> does a few
>> >> >things correct which are probably overseen easily. The
>> >> addition works
>> >> >in HEAD already and paases all memcheck tests idid so far.
>> 
>> 
>> 
>> 





Best regards,
 Marcus
Index: ext/spl/php_spl.c
===================================================================
RCS file: /repository/php-src/ext/spl/php_spl.c,v
retrieving revision 1.52.2.28.2.1
diff -u -p -d -r1.52.2.28.2.1 php_spl.c
--- ext/spl/php_spl.c   4 Jun 2006 10:47:22 -0000       1.52.2.28.2.1
+++ ext/spl/php_spl.c   4 Jun 2006 11:18:11 -0000
@@ -610,7 +610,14 @@ PHP_MINFO_FUNCTION(spl)
 
 static
 ZEND_BEGIN_ARG_INFO(arginfo_iterator, 0)
-       ZEND_ARG_INFO(0, iterator)
+       ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_iterator_apply, 0, 0, 2)
+       ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+       ZEND_ARG_INFO(0, function)
+       ZEND_ARG_ARRAY_INFO(0, args, 1)
 ZEND_END_ARG_INFO();
 
 /* {{{ spl_functions
@@ -628,6 +635,7 @@ zend_function_entry spl_functions[] = {
 #ifdef SPL_ITERATORS_H
        PHP_FE(iterator_to_array,       arginfo_iterator)
        PHP_FE(iterator_count,          arginfo_iterator)
+       PHP_FE(iterator_apply,          arginfo_iterator_apply)
 #endif /* SPL_ITERATORS_H */
        {NULL, NULL, NULL}
 };
Index: ext/spl/spl_iterators.c
===================================================================
RCS file: /repository/php-src/ext/spl/spl_iterators.c,v
retrieving revision 1.73.2.30.2.9
diff -u -p -d -r1.73.2.30.2.9 spl_iterators.c
--- ext/spl/spl_iterators.c     21 May 2006 18:13:37 -0000      1.73.2.30.2.9
+++ ext/spl/spl_iterators.c     4 Jun 2006 11:18:12 -0000
@@ -2612,6 +2612,54 @@ PHP_FUNCTION(iterator_count)
 }
 /* }}} */
 
+typedef struct {
+       zval                   *obj;
+       zval                   *args;
+       long                   count;
+       zend_fcall_info        fci;
+       zend_fcall_info_cache  fcc;
+} spl_iterator_apply_info;
+
+static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser 
TSRMLS_DC) /* {{{ */
+{
+       zval *retval;
+       spl_iterator_apply_info  *apply_info = (spl_iterator_apply_info*)puser;
+       int result;
+
+       apply_info->count++;
+       zend_fcall_info_call(&apply_info->fci, &apply_info->fcc, &retval, NULL 
TSRMLS_CC);
+       if (retval) {
+               result = zend_is_true(retval) ? ZEND_HASH_APPLY_KEEP : 
ZEND_HASH_APPLY_STOP;
+               zval_ptr_dtor(&retval);
+       } else {
+               result = ZEND_HASH_APPLY_STOP;
+       }
+       return result;
+}
+/* }}} */
+
+/* {{{ proto int iterator_apply(Traversable it, mixed function [, mixed 
params])
+   Calls a function for every element in an iterator */
+PHP_FUNCTION(iterator_apply)
+{
+       spl_iterator_apply_info  apply_info;
+
+       apply_info.args = NULL;
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Of|a!", 
&apply_info.obj, zend_ce_traversable, &apply_info.fci, &apply_info.fcc, 
&apply_info.args) == FAILURE) {
+               return;
+       }
+
+       apply_info.count = 0;
+       zend_fcall_info_args(&apply_info.fci, apply_info.args TSRMLS_CC);
+       if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, 
(void*)&apply_info TSRMLS_CC) == SUCCESS) {
+               RETVAL_LONG(apply_info.count);
+       } else {
+               RETVAL_FALSE;
+       }
+       zend_fcall_info_args(&apply_info.fci, NULL TSRMLS_CC);
+}
+/* }}} */
+
 static zend_function_entry spl_funcs_OuterIterator[] = {
        SPL_ABSTRACT_ME(OuterIterator, getInnerIterator,   NULL)
        {NULL, NULL, NULL}
Index: ext/spl/spl_iterators.h
===================================================================
RCS file: /repository/php-src/ext/spl/spl_iterators.h,v
retrieving revision 1.18.2.7.2.5
diff -u -p -d -r1.18.2.7.2.5 spl_iterators.h
--- ext/spl/spl_iterators.h     21 May 2006 18:13:37 -0000      1.18.2.7.2.5
+++ ext/spl/spl_iterators.h     4 Jun 2006 11:18:12 -0000
@@ -55,6 +55,7 @@ PHP_MINIT_FUNCTION(spl_iterators);
 
 PHP_FUNCTION(iterator_to_array);
 PHP_FUNCTION(iterator_count);
+PHP_FUNCTION(iterator_apply);
 
 typedef enum {
        DIT_Default = 0,
Index: ext/spl/tests/spl_004.phpt
===================================================================
RCS file: ext/spl/tests/spl_004.phpt
diff -N ext/spl/tests/spl_004.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ext/spl/tests/spl_004.phpt  4 Jun 2006 11:18:12 -0000
@@ -0,0 +1,86 @@
+--TEST--
+SPL: iterator_apply()
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+function my_error_handler($errno, $errstr, $errfile, $errline) {
+       echo "Error: $errstr\n";
+}
+
+set_error_handler('my_error_handler');
+
+function test_arg($arg)
+{
+       if ($arg instanceof Iterator)
+       {
+               var_dump($arg->key());
+               var_dump($arg->current());
+       }
+       else
+       {
+               var_dump($arg);
+       }
+       return true;
+}
+
+function test()
+{
+       static $arg = 0;
+       var_dump($arg++);
+       return true;
+}
+
+$it = new RecursiveArrayIterator(array(1, array(21, 22), 3));
+
+var_dump(iterator_apply($it, 'test', NULL));
+
+echo "===ARGS===\n";
+var_dump(iterator_apply($it, 'test_arg', array($it)));
+
+echo "===RECURSIVE===\n";
+$it = new RecursiveIteratorIterator($it);
+var_dump(iterator_apply($it, 'test'));
+
+echo "===ERRORS===\n";
+var_dump(iterator_apply($it, 'test', 1));
+var_dump(iterator_apply($it, 'non_existing_functon'));
+var_dump(iterator_apply($it, 'non_existing_functon', NULL, 2));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(0)
+int(1)
+int(2)
+int(3)
+===ARGS===
+int(0)
+int(1)
+int(1)
+array(2) {
+  [0]=>
+  int(21)
+  [1]=>
+  int(22)
+}
+int(2)
+int(3)
+int(3)
+===RECURSIVE===
+int(3)
+int(4)
+int(5)
+int(6)
+int(4)
+===ERRORS===
+Error: Argument 3 passed to iterator_apply() must be an array, integer given
+Error: iterator_apply() expects parameter 3 to be array, integer given
+NULL
+Error: iterator_apply() expects parameter 2 to be function,%sstring given
+NULL
+Error: iterator_apply() expects at most 3 parameters, 4 given
+NULL
+===DONE===
Index: Zend/zend_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.296.2.27.2.14
diff -u -p -d -r1.296.2.27.2.14 zend_API.c
--- Zend/zend_API.c     4 Jun 2006 10:27:28 -0000       1.296.2.27.2.14
+++ Zend/zend_API.c     4 Jun 2006 12:10:29 -0000
@@ -547,6 +547,22 @@ static char *zend_parse_arg_impl(int arg
                        }
                        break;
 
+               case 'f':
+                       {
+                               zend_fcall_info       *fci = va_arg(*va, 
zend_fcall_info *);
+                               zend_fcall_info_cache *fcc = va_arg(*va, 
zend_fcall_info_cache *);
+
+                               if (zend_fcall_info_init(*arg, fci, fcc 
TSRMLS_CC) == SUCCESS) {
+                                       break;
+                               } else if (return_null) {
+                                       fci->size = 0;
+                                       fcc->initialized = 0;
+                                       break;
+                               } else {
+                                       return "function";
+                               }
+                       }
+
                case 'z':
                        {
                                zval **p = va_arg(*va, zval **);
@@ -2300,6 +2316,96 @@ ZEND_API zend_bool zend_make_callable(zv
 }
 
 
+ZEND_API int zend_fcall_info_init(zval *callable, zend_fcall_info *fci, 
zend_fcall_info_cache *fcc TSRMLS_DC)
+{
+       zend_class_entry *ce;
+       zend_function    *func;
+       zval             **obj;
+
+       if (!zend_is_callable_ex(callable, IS_CALLABLE_STRICT, NULL, NULL, &ce, 
&func, &obj TSRMLS_CC)) {
+               return FAILURE;
+       }
+
+       fci->size = sizeof(*fci);
+       fci->function_table = ce ? &ce->function_table : EG(function_table);
+       fci->object_pp = obj;
+       fci->function_name = NULL;
+       fci->retval_ptr_ptr = NULL;
+       fci->param_count = 0;
+       fci->params = NULL;
+       fci->no_separation = 1;
+       fci->symbol_table = NULL;
+
+       fcc->initialized = 1;
+       fcc->function_handler = func;
+       fcc->calling_scope = ce;
+       fcc->object_pp = obj;
+
+       return SUCCESS;
+}
+
+
+ZEND_API int zend_fcall_info_args(zend_fcall_info *fci, zval *args TSRMLS_DC)
+{
+       HashPosition pos;
+       zval         **arg, ***params;
+
+       if (fci->params) {
+               while (fci->param_count) {
+                       zval_ptr_dtor(fci->params[--fci->param_count]);
+               }
+               efree(fci->params);
+       }
+       fci->params = NULL;
+       fci->param_count = 0;
+
+       if (!args) {
+               return SUCCESS;
+       }
+
+       if (Z_TYPE_P(args) != IS_ARRAY) {
+               return FAILURE;
+       }
+
+       fci->param_count = zend_hash_num_elements(Z_ARRVAL_P(args));
+       fci->params = params = (zval***)safe_emalloc(sizeof(zval**), 
fci->param_count, 0);
+
+       zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos);
+
+       while (zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void **) &arg, 
&pos) == SUCCESS) {
+               *params++ = arg;
+               (*arg)->refcount++;
+               zend_hash_move_forward_ex(Z_ARRVAL_P(args), &pos);
+       }
+       return SUCCESS;
+}
+
+
+ZEND_API int zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache 
*fcc, zval **retval_ptr_ptr, zval *args TSRMLS_DC)
+{
+       zval *retval, ***org_params;
+       int  result, org_count;
+
+       fci->retval_ptr_ptr = retval_ptr_ptr ? retval_ptr_ptr : &retval;
+       if (args) {
+               org_params = fci->params;
+               org_count = fci->param_count;
+               zend_fcall_info_args(fci, args TSRMLS_CC);
+       }
+       result = zend_call_function(fci, fcc TSRMLS_CC);
+       
+       if (!retval_ptr_ptr && retval) {
+               zval_ptr_dtor(&retval);
+       }
+       if (args) {
+               zend_fcall_info_args(fci, NULL TSRMLS_CC);
+               fci->params = org_params;
+               fci->param_count = org_count;
+       }
+       return result;
+}
+
+
 ZEND_API char *zend_get_module_version(char *module_name)
 {
        zend_module_entry *module;
Index: Zend/zend_API.h
===================================================================
RCS file: /repository/ZendEngine2/zend_API.h,v
retrieving revision 1.207.2.8.2.2
diff -u -p -d -r1.207.2.8.2.2 zend_API.h
--- Zend/zend_API.h     25 May 2006 10:01:06 -0000      1.207.2.8.2.2
+++ Zend/zend_API.h     4 Jun 2006 12:10:30 -0000
@@ -385,6 +385,26 @@ typedef struct _zend_fcall_info_cache {
 BEGIN_EXTERN_C()
 ZEND_API extern zend_fcall_info_cache empty_fcall_info_cache;
 
+/** Build zend_call_info/cache from a zval*
+ *
+ * Caller is responsible to provide a return value, otherwise the we will 
crash. 
+ * fci->retval_ptr_ptr = NULL;
+ * In order to pass parameters the following members need to be set:
+ * fci->param_count = 0;
+ * fci->params = NULL;
+ */
+ZEND_API int zend_fcall_info_init(zval *callable, zend_fcall_info *fci, 
zend_fcall_info_cache *fcc TSRMLS_DC);
+
+/** Set or clear the arguments in the zend_call_info struct taking care of
+ * refcount. If args is NULL and arguments are set then those are cleared.
+ */
+ZEND_API int zend_fcall_info_args(zend_fcall_info *fci, zval *args TSRMLS_DC);
+
+/** Call a function using information created by zend_fcall_info_init()/args().
+ * If args is given then those replace the arguement info in fci is 
temporarily.
+ */
+ZEND_API int zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache 
*fcc, zval **retval, zval *args TSRMLS_DC);
+
 ZEND_API int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache 
*fci_cache TSRMLS_DC);
 
 
-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to