Skip to content

Commit 114de5b

Browse files
committed
Implement json_encode, fix reference counting
1 parent eede376 commit 114de5b

File tree

6 files changed

+58
-2
lines changed

6 files changed

+58
-2
lines changed

ext/spl/config.m4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c sp
22
PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h spl_cachediterable.h])
33
PHP_ADD_EXTENSION_DEP(spl, pcre, true)
44
PHP_ADD_EXTENSION_DEP(spl, standard, true)
5+
PHP_ADD_EXTENSION_DEP(spl, json, true)

ext/spl/spl_cachediterable.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ static HashTable* spl_cachediterable_object_get_properties(zend_object *obj)
304304
/* Initialize properties array */
305305
for (size_t i = 0; i < len; i++) {
306306
zval tmp;
307+
Z_TRY_ADDREF_P(&entries[i].key);
308+
Z_TRY_ADDREF_P(&entries[i].value);
307309
ZVAL_ARR(&tmp, zend_new_pair(&entries[i].key, &entries[i].value));
308310
zend_hash_index_update(ht, i++, &tmp);
309311
}
@@ -720,6 +722,33 @@ PHP_METHOD(CachedIterable, valueAt)
720722
RETURN_COPY(&intern->array.entries[offset].value);
721723
}
722724

725+
PHP_METHOD(CachedIterable, jsonSerialize)
726+
{
727+
/* json_encoder.c will always encode objects as {"0":..., "1":...}, and detects recursion if an object returns its internal property array */
728+
ZEND_PARSE_PARAMETERS_NONE();
729+
spl_cachediterable_object *intern = Z_CACHEDITERABLE_P(ZEND_THIS);
730+
size_t len = intern->array.size;
731+
if (!len) {
732+
RETURN_EMPTY_ARRAY();
733+
}
734+
735+
zval_pair *entries = intern->array.entries;
736+
zend_array *values = zend_new_array(len);
737+
/* Initialize return array */
738+
zend_hash_real_init_packed(values);
739+
740+
/* Go through values and add values to the return array */
741+
ZEND_HASH_FILL_PACKED(values) {
742+
for (size_t i = 0; i < len; i++) {
743+
zval tmp;
744+
Z_TRY_ADDREF_P(&entries[i].key);
745+
Z_TRY_ADDREF_P(&entries[i].value);
746+
ZVAL_ARR(&tmp, zend_new_pair(&entries[i].key, &entries[i].value));
747+
ZEND_HASH_FILL_ADD(&tmp);
748+
}
749+
} ZEND_HASH_FILL_END();
750+
RETURN_ARR(values);
751+
}
723752

724753
PHP_MINIT_FUNCTION(spl_cachediterable)
725754
{
@@ -736,6 +765,7 @@ PHP_MINIT_FUNCTION(spl_cachediterable)
736765

737766
REGISTER_SPL_IMPLEMENTS(CachedIterable, Aggregate);
738767
REGISTER_SPL_IMPLEMENTS(CachedIterable, Countable);
768+
REGISTER_SPL_IMPLEMENTS(CachedIterable, JsonSerializable);
739769

740770
spl_ce_CachedIterable->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES;
741771
spl_ce_CachedIterable->get_iterator = spl_cachediterable_get_iterator;

ext/spl/spl_cachediterable.stub.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22

33
/** @generate-function-entries */
4-
final class CachedIterable implements IteratorAggregate, Countable
4+
final class CachedIterable implements IteratorAggregate, Countable, JsonSerializable
55
{
66
public function __construct(iterable $iterator) {}
77
public function getIterator(): InternalIterator {}
@@ -15,4 +15,6 @@ public function keys(): array {}
1515
public function values(): array {}
1616
public function keyAt(int $offset): mixed {}
1717
public function valueAt(int $offset): mixed {}
18+
19+
public function jsonSerialize(): array {}
1820
}

ext/spl/spl_cachediterable_arginfo.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: ef7b757105d968778ef91cfebadfa51b559e2f7e */
2+
* Stub hash: c1b5d7c534af712125691bf95c8210787fd012bf */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_CachedIterable___construct, 0, 0, 1)
55
ZEND_ARG_TYPE_INFO(0, iterator, IS_ITERABLE, 0)
@@ -32,6 +32,8 @@ ZEND_END_ARG_INFO()
3232

3333
#define arginfo_class_CachedIterable_valueAt arginfo_class_CachedIterable_keyAt
3434

35+
#define arginfo_class_CachedIterable_jsonSerialize arginfo_class_CachedIterable___serialize
36+
3537

3638
ZEND_METHOD(CachedIterable, __construct);
3739
ZEND_METHOD(CachedIterable, getIterator);
@@ -43,6 +45,7 @@ ZEND_METHOD(CachedIterable, keys);
4345
ZEND_METHOD(CachedIterable, values);
4446
ZEND_METHOD(CachedIterable, keyAt);
4547
ZEND_METHOD(CachedIterable, valueAt);
48+
ZEND_METHOD(CachedIterable, jsonSerialize);
4649

4750

4851
static const zend_function_entry class_CachedIterable_methods[] = {
@@ -56,5 +59,6 @@ static const zend_function_entry class_CachedIterable_methods[] = {
5659
ZEND_ME(CachedIterable, values, arginfo_class_CachedIterable_values, ZEND_ACC_PUBLIC)
5760
ZEND_ME(CachedIterable, keyAt, arginfo_class_CachedIterable_keyAt, ZEND_ACC_PUBLIC)
5861
ZEND_ME(CachedIterable, valueAt, arginfo_class_CachedIterable_valueAt, ZEND_ACC_PUBLIC)
62+
ZEND_ME(CachedIterable, jsonSerialize, arginfo_class_CachedIterable_jsonSerialize, ZEND_ACC_PUBLIC)
5963
ZEND_FE_END
6064
};

ext/spl/spl_iterators.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "php.h"
2121
#include "php_spl.h"
2222
#include "ext/pcre/php_pcre.h"
23+
#include "ext/json/php_json.h"
2324

2425
#define spl_ce_Traversable zend_ce_traversable
2526
#define spl_ce_Iterator zend_ce_iterator
@@ -28,6 +29,7 @@
2829
#define spl_ce_Serializable zend_ce_serializable
2930
#define spl_ce_Countable zend_ce_countable
3031
#define spl_ce_Stringable zend_ce_stringable
32+
#define spl_ce_JsonSerializable php_json_serializable_ce
3133

3234
extern PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
3335
extern PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;

ext/spl/tests/CachedIterable/CachedIterable_serialization.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ $x = 'modified'; // no effect, this is copied by value
2424
var_dump($it->__serialize());
2525
$it = new CachedIterable([]);
2626
var_dump($it->__serialize());
27+
28+
$it = CachedIterable::fromPairs([[new stdClass(), &$x]]);
29+
echo "json encoded: " . var_export(json_encode($it), true) . "\n";
30+
echo "json encoded empty: " . var_export(json_encode($it), true) . "\n";
31+
var_dump($it);
2732
?>
2833
--EXPECT--
2934
Caught Error: Cannot create dynamic property CachedIterable::$dynamicProp
@@ -49,4 +54,16 @@ array(2) {
4954
int(123)
5055
}
5156
array(0) {
57+
}
58+
json encoded: '[[{},"modified"]]'
59+
json encoded empty: '[[{},"modified"]]'
60+
object(CachedIterable)#6 (1) {
61+
[0]=>
62+
array(2) {
63+
[0]=>
64+
object(stdClass)#4 (0) {
65+
}
66+
[1]=>
67+
string(8) "modified"
68+
}
5269
}

0 commit comments

Comments
 (0)