@@ -5777,12 +5777,16 @@ static int php_traversable_reduce_elem(zend_object_iterator *iter, void *puser)
5777
5777
ZEND_ASSERT (ZEND_FCI_INITIALIZED (* fci ));
5778
5778
5779
5779
zval * operand = iter -> funcs -> get_current_data (iter );
5780
- ZVAL_COPY_VALUE (& fci -> params [0 ], fci -> retval );
5781
- ZVAL_COPY (& fci -> params [1 ], operand );
5780
+ if (UNEXPECTED (!operand || EG (exception ))) {
5781
+ return ZEND_HASH_APPLY_STOP ;
5782
+ }
5783
+ ZVAL_DEREF (operand );
5784
+ ZVAL_COPY_VALUE (& reduce_data -> args [0 ], fci -> retval );
5785
+ ZVAL_COPY (& reduce_data -> args [1 ], operand );
5782
5786
ZVAL_NULL (fci -> retval );
5783
5787
int result = zend_call_function (& reduce_data -> fci , & reduce_data -> fcc );
5784
5788
zval_ptr_dtor (operand );
5785
- zval_ptr_dtor (& fci -> params [0 ]);
5789
+ zval_ptr_dtor (& reduce_data -> args [0 ]);
5786
5790
if (UNEXPECTED (result == FAILURE || EG (exception ))) {
5787
5791
return ZEND_HASH_APPLY_STOP ;
5788
5792
}
@@ -5791,12 +5795,11 @@ static int php_traversable_reduce_elem(zend_object_iterator *iter, void *puser)
5791
5795
5792
5796
static zend_always_inline void php_traversable_reduce (zval * obj , zend_fcall_info fci , zend_fcall_info_cache fci_cache , zval * return_value ) /* {{{ */
5793
5797
{
5794
- zval args [2 ];
5795
5798
traversable_reduce_data reduce_data ;
5796
5799
reduce_data .fci = fci ;
5797
5800
reduce_data .fci .retval = return_value ;
5798
5801
reduce_data .fci .param_count = 2 ;
5799
- reduce_data .fci .params = args ;
5802
+ reduce_data .fci .params = reduce_data . args ;
5800
5803
reduce_data .fcc = fci_cache ;
5801
5804
5802
5805
spl_iterator_apply (obj , php_traversable_reduce_elem , (void * )& reduce_data );
@@ -6236,7 +6239,7 @@ PHP_FUNCTION(array_combine)
6236
6239
static inline void php_array_until (zval * return_value , HashTable * htbl , zend_fcall_info fci , zend_fcall_info_cache fci_cache , int stop_value , int negate ) /* {{{ */
6237
6240
{
6238
6241
zval args [1 ];
6239
- zend_bool have_callback = 0 ;
6242
+ bool have_callback = 0 ;
6240
6243
zval * operand ;
6241
6244
zval retval ;
6242
6245
int result ;
@@ -6254,7 +6257,7 @@ static inline void php_array_until(zval *return_value, HashTable *htbl, zend_fca
6254
6257
6255
6258
ZEND_HASH_FOREACH_VAL (htbl , operand ) {
6256
6259
if (have_callback ) {
6257
- zend_bool retval_true ;
6260
+ bool retval_true ;
6258
6261
ZVAL_COPY (& args [0 ], operand );
6259
6262
6260
6263
/* Treat the operand like an array of size 1 */
@@ -6296,11 +6299,16 @@ static int php_traversable_func_until(zend_object_iterator *iter, void *puser) /
6296
6299
zval retval ;
6297
6300
php_iterator_until_info * until_info = (php_iterator_until_info * ) puser ;
6298
6301
int result ;
6299
- zend_bool stop ;
6302
+ bool stop ;
6300
6303
6301
6304
fci = until_info -> fci ;
6302
6305
if (ZEND_FCI_INITIALIZED (fci )) {
6303
6306
zval * operand = iter -> funcs -> get_current_data (iter );
6307
+ if (UNEXPECTED (!operand || EG (exception ))) {
6308
+ until_info -> result = FAILURE ;
6309
+ return ZEND_HASH_APPLY_STOP ;
6310
+ }
6311
+ ZVAL_DEREF (operand );
6304
6312
fci .retval = & retval ;
6305
6313
fci .param_count = 1 ;
6306
6314
/* Use the operand like an array of size 1 */
@@ -6317,7 +6325,13 @@ static int php_traversable_func_until(zend_object_iterator *iter, void *puser) /
6317
6325
stop = zend_is_true (& retval ) == until_info -> stop_value ;
6318
6326
zval_ptr_dtor (& retval );
6319
6327
} else {
6320
- stop = zend_is_true (iter -> funcs -> get_current_data (iter )) == until_info -> stop_value ;
6328
+ zval * operand = iter -> funcs -> get_current_data (iter );
6329
+ if (UNEXPECTED (!operand || EG (exception ))) {
6330
+ return ZEND_HASH_APPLY_STOP ;
6331
+ }
6332
+ ZVAL_DEREF (operand );
6333
+ stop = zend_is_true (operand ) == until_info -> stop_value ;
6334
+ zval_ptr_dtor (operand );
6321
6335
}
6322
6336
if (stop ) {
6323
6337
until_info -> found = 1 ;
@@ -6390,7 +6404,7 @@ PHP_FUNCTION(reduce)
6390
6404
{
6391
6405
zval * input ;
6392
6406
zend_fcall_info fci ;
6393
- zend_fcall_info_cache fci_cache = empty_fcall_info_cache ;
6407
+ zend_fcall_info_cache fci_cache ;
6394
6408
zval * initial = NULL ;
6395
6409
6396
6410
ZEND_PARSE_PARAMETERS_START (2 , 3 )
@@ -6419,3 +6433,132 @@ PHP_FUNCTION(reduce)
6419
6433
}
6420
6434
}
6421
6435
/* }}} */
6436
+
6437
+ static zend_always_inline void php_array_find (HashTable * htbl , zend_fcall_info fci , zend_fcall_info_cache fci_cache , zval * return_value , zval * default_value ) /* {{{ */
6438
+ {
6439
+ zval retval ;
6440
+ zval * operand ;
6441
+
6442
+ if (zend_hash_num_elements (htbl ) > 0 ) {
6443
+ fci .retval = & retval ;
6444
+ fci .param_count = 1 ;
6445
+
6446
+ ZEND_HASH_FOREACH_VAL (htbl , operand ) {
6447
+ fci .params = operand ;
6448
+ Z_TRY_ADDREF_P (operand );
6449
+
6450
+ if (zend_call_function (& fci , & fci_cache ) == SUCCESS ) {
6451
+ bool found = zend_is_true (& retval );
6452
+ if (found ) {
6453
+ ZVAL_COPY_VALUE (return_value , operand );
6454
+ return ;
6455
+ } else {
6456
+ zval_ptr_dtor (operand );
6457
+ }
6458
+ } else {
6459
+ zval_ptr_dtor (operand );
6460
+ return ;
6461
+ }
6462
+ } ZEND_HASH_FOREACH_END ();
6463
+ }
6464
+
6465
+ if (default_value ) {
6466
+ ZVAL_COPY (return_value , default_value );
6467
+ } else {
6468
+ ZVAL_NULL (return_value );
6469
+ }
6470
+ }
6471
+ /* }}} */
6472
+
6473
+ typedef struct {
6474
+ zend_fcall_info fci ;
6475
+ zend_fcall_info_cache fcc ;
6476
+ zval * return_value ;
6477
+ bool found ;
6478
+ } traversable_find_data ;
6479
+
6480
+ static int php_traversable_find_elem (zend_object_iterator * iter , void * puser ) /* {{{ */
6481
+ {
6482
+ zval retval ;
6483
+ traversable_find_data * find_data = puser ;
6484
+ zend_fcall_info * fci = & find_data -> fci ;
6485
+ ZEND_ASSERT (ZEND_FCI_INITIALIZED (* fci ));
6486
+
6487
+ zval * operand = iter -> funcs -> get_current_data (iter );
6488
+ if (UNEXPECTED (!operand || EG (exception ))) {
6489
+ return ZEND_HASH_APPLY_STOP ;
6490
+ }
6491
+ ZVAL_DEREF (operand );
6492
+ // Treat this as a 1-element array.
6493
+ fci -> params = operand ;
6494
+ fci -> retval = & retval ;
6495
+ Z_TRY_ADDREF_P (operand );
6496
+ int result = zend_call_function (& find_data -> fci , & find_data -> fcc );
6497
+ if (UNEXPECTED (result == FAILURE || EG (exception ))) {
6498
+ return ZEND_HASH_APPLY_STOP ;
6499
+ }
6500
+ fci -> retval = & retval ;
6501
+ bool found = zend_is_true (& retval );
6502
+ zval_ptr_dtor (& retval );
6503
+ if (UNEXPECTED (EG (exception ))) {
6504
+ return ZEND_HASH_APPLY_STOP ;
6505
+ }
6506
+ if (found ) {
6507
+ ZVAL_COPY_VALUE (find_data -> return_value , operand );
6508
+ find_data -> found = 1 ;
6509
+ return ZEND_HASH_APPLY_STOP ;
6510
+ }
6511
+ zval_ptr_dtor (operand );
6512
+ return ZEND_HASH_APPLY_KEEP ;
6513
+ }
6514
+
6515
+ static zend_always_inline void php_traversable_find (zval * obj , zend_fcall_info fci , zend_fcall_info_cache fci_cache , zval * return_value , zval * default_value ) /* {{{ */
6516
+ {
6517
+ traversable_find_data find_data ;
6518
+ find_data .fci = fci ;
6519
+ find_data .fci .param_count = 1 ;
6520
+ find_data .fcc = fci_cache ;
6521
+ find_data .return_value = return_value ;
6522
+ find_data .found = 0 ;
6523
+
6524
+ if (spl_iterator_apply (obj , php_traversable_find_elem , (void * )& find_data ) != SUCCESS || EG (exception )) {
6525
+ return ;
6526
+ }
6527
+ if (find_data .found ) {
6528
+ return ;
6529
+ }
6530
+ if (default_value ) {
6531
+ ZVAL_COPY (return_value , default_value );
6532
+ } else {
6533
+ ZVAL_NULL (return_value );
6534
+ }
6535
+ }
6536
+ /* }}} */
6537
+
6538
+ /* {{{ Finds the first value or returns the default */
6539
+ PHP_FUNCTION (find )
6540
+ {
6541
+ zval * input ;
6542
+ zend_fcall_info fci ;
6543
+ zend_fcall_info_cache fci_cache ;
6544
+ zval * default_value = NULL ;
6545
+
6546
+ ZEND_PARSE_PARAMETERS_START (2 , 3 )
6547
+ Z_PARAM_ITERABLE (input )
6548
+ Z_PARAM_FUNC (fci , fci_cache )
6549
+ Z_PARAM_OPTIONAL
6550
+ Z_PARAM_ZVAL (default_value )
6551
+ ZEND_PARSE_PARAMETERS_END ();
6552
+
6553
+ switch (Z_TYPE_P (input )) {
6554
+ case IS_ARRAY :
6555
+ php_array_find (Z_ARRVAL_P (input ), fci , fci_cache , return_value , default_value );
6556
+ return ;
6557
+ case IS_OBJECT : {
6558
+ php_traversable_find (input , fci , fci_cache , return_value , default_value );
6559
+ return ;
6560
+ }
6561
+ EMPTY_SWITCH_DEFAULT_CASE ();
6562
+ }
6563
+ }
6564
+ /* }}} */
0 commit comments