mirror of
https://github.com/php/php-src.git
synced 2024-11-27 20:03:40 +08:00
Introduce InternalIterator
Userland classes that implement Traversable must do so either through Iterator or IteratorAggregate. The same requirement does not exist for internal classes: They can implement the internal get_iterator mechanism, without exposing either the Iterator or IteratorAggregate APIs. This makes them usable in get_iterator(), but incompatible with any Iterator based APIs. A lot of internal classes do this, because exposing the userland APIs is simply a lot of work. This patch alleviates this issue by providing a generic InternalIterator class, which acts as an adapater between get_iterator and Iterator, and can be easily used by many internal classes. At the same time, we extend the requirement that Traversable implies Iterator or IteratorAggregate to internal classes as well. Closes GH-5216.
This commit is contained in:
parent
4730b06f1d
commit
ff19ec2df3
15
UPGRADING
15
UPGRADING
@ -766,6 +766,17 @@ PHP 8.0 UPGRADE NOTES
|
||||
longer referenced.
|
||||
. The deprecated parameter `$version` of curl_version() has been removed.
|
||||
|
||||
- Date:
|
||||
. DatePeriod now implements IteratorAggregate (instead of Traversable).
|
||||
|
||||
- DOM:
|
||||
. DOMNamedNodeMap now implements IteratorAggregate (instead of Traversable).
|
||||
. DOMNodeList now implements IteratorAggregate (instead of Traversable).
|
||||
|
||||
- Intl:
|
||||
. IntlBreakIterator now implements IteratorAggregate (instead of Traversable).
|
||||
. ResourceBundle now implements IteratorAggregate (instead of Traversable).
|
||||
|
||||
- Enchant:
|
||||
. The enchant extension now uses libenchant-2 by default when available.
|
||||
libenchant version 1 is still supported but is deprecated and could
|
||||
@ -786,9 +797,13 @@ PHP 8.0 UPGRADE NOTES
|
||||
- MBString:
|
||||
. The Unicode data tables have been updated to version 13.0.0.
|
||||
|
||||
- PDO:
|
||||
. PDOStatement now implements IteratorAggregate (instead of Traversable).
|
||||
|
||||
- MySQLi / PDO MySQL:
|
||||
. When mysqlnd is not used (which is the default and recommended option),
|
||||
the minimum supported libmysqlclient version is now 5.1.
|
||||
. mysqli_result now implements IteratorAggregate (instead of Traversable).
|
||||
|
||||
- PGSQL / PDO PGSQL:
|
||||
. The PGSQL and PDO PGSQL extensions now require at least libpq 9.1.
|
||||
|
@ -18,6 +18,7 @@ PHP 8.0 INTERNALS UPGRADE NOTES
|
||||
o. cast_object() object handler is now required
|
||||
p. ARG_COUNT() macro removed
|
||||
q. GC_COLLECTABLE flag
|
||||
r. Cannot implement Traversable only
|
||||
|
||||
2. Build system changes
|
||||
a. Abstract
|
||||
@ -122,6 +123,16 @@ PHP 8.0 INTERNALS UPGRADE NOTES
|
||||
Assignments to GC_TYPE_INFO() might need to be changed to properly
|
||||
set the value of the GC_NOT_COLLECTABLE flag.
|
||||
|
||||
r. Just for for userland classes, it is no longer allowed to implement only
|
||||
the Traversable interface. Instead, it is necessary to implement either
|
||||
Iterator or IteratorAggregate. You can do the latter by implementing
|
||||
zend_ce_aggregate and providing the following method implementation:
|
||||
|
||||
ZEND_METHOD(MyClass, getIterator) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||
}
|
||||
|
||||
========================
|
||||
2. Build system changes
|
||||
========================
|
||||
|
@ -29,6 +29,9 @@ ZEND_API zend_class_entry *zend_ce_arrayaccess;
|
||||
ZEND_API zend_class_entry *zend_ce_serializable;
|
||||
ZEND_API zend_class_entry *zend_ce_countable;
|
||||
ZEND_API zend_class_entry *zend_ce_stringable;
|
||||
ZEND_API zend_class_entry *zend_ce_internal_iterator;
|
||||
|
||||
static zend_object_handlers zend_internal_iterator_handlers;
|
||||
|
||||
/* {{{ zend_call_method
|
||||
Only returns the returned zval if retval_ptr != NULL */
|
||||
@ -246,20 +249,16 @@ ZEND_API zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *c
|
||||
/* {{{ zend_implement_traversable */
|
||||
static int zend_implement_traversable(zend_class_entry *interface, zend_class_entry *class_type)
|
||||
{
|
||||
/* check that class_type is traversable at c-level or implements at least one of 'aggregate' and 'Iterator' */
|
||||
uint32_t i;
|
||||
|
||||
if (class_type->get_iterator || (class_type->parent && class_type->parent->get_iterator)) {
|
||||
return SUCCESS;
|
||||
}
|
||||
/* Abstract class can implement Traversable only, in which case the extending class must
|
||||
* implement Iterator or IteratorAggregate. */
|
||||
if (class_type->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* Check that class_type implements at least one of 'IteratorAggregate' or 'Iterator' */
|
||||
if (class_type->num_interfaces) {
|
||||
ZEND_ASSERT(class_type->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
|
||||
for (i = 0; i < class_type->num_interfaces; i++) {
|
||||
for (uint32_t i = 0; i < class_type->num_interfaces; i++) {
|
||||
if (class_type->interfaces[i] == zend_ce_aggregate || class_type->interfaces[i] == zend_ce_iterator) {
|
||||
return SUCCESS;
|
||||
}
|
||||
@ -441,9 +440,169 @@ static int zend_implement_serializable(zend_class_entry *interface, zend_class_e
|
||||
}
|
||||
/* }}}*/
|
||||
|
||||
typedef struct {
|
||||
zend_object std;
|
||||
zend_object_iterator *iter;
|
||||
zend_bool rewind_called;
|
||||
} zend_internal_iterator;
|
||||
|
||||
static zend_object *zend_internal_iterator_create(zend_class_entry *ce) {
|
||||
zend_internal_iterator *intern = emalloc(sizeof(zend_internal_iterator));
|
||||
zend_object_std_init(&intern->std, ce);
|
||||
intern->std.handlers = &zend_internal_iterator_handlers;
|
||||
intern->iter = NULL;
|
||||
intern->rewind_called = 0;
|
||||
return &intern->std;
|
||||
}
|
||||
|
||||
ZEND_API int zend_create_internal_iterator_zval(zval *return_value, zval *obj) {
|
||||
zend_class_entry *scope = EG(current_execute_data)->func->common.scope;
|
||||
ZEND_ASSERT(scope->get_iterator != zend_user_it_get_new_iterator);
|
||||
zend_object_iterator *iter = scope->get_iterator(Z_OBJCE_P(obj), obj, /* by_ref */ 0);
|
||||
if (!iter) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
zend_internal_iterator *intern =
|
||||
(zend_internal_iterator *) zend_internal_iterator_create(zend_ce_internal_iterator);
|
||||
intern->iter = iter;
|
||||
ZVAL_OBJ(return_value, &intern->std);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static void zend_internal_iterator_free(zend_object *obj) {
|
||||
zend_internal_iterator *intern = (zend_internal_iterator *) obj;
|
||||
if (intern->iter) {
|
||||
zend_iterator_dtor(intern->iter);
|
||||
}
|
||||
zend_object_std_dtor(&intern->std);
|
||||
}
|
||||
|
||||
static zend_internal_iterator *zend_internal_iterator_fetch(zval *This) {
|
||||
zend_internal_iterator *intern = (zend_internal_iterator *) Z_OBJ_P(This);
|
||||
if (!intern->iter) {
|
||||
zend_throw_error(NULL, "The InternalIterator object has not been properly initialized");
|
||||
return NULL;
|
||||
}
|
||||
return intern;
|
||||
}
|
||||
|
||||
/* Many iterators will not behave correctly if rewind() is not called, make sure it happens. */
|
||||
static int zend_internal_iterator_ensure_rewound(zend_internal_iterator *intern) {
|
||||
if (!intern->rewind_called) {
|
||||
zend_object_iterator *iter = intern->iter;
|
||||
intern->rewind_called = 1;
|
||||
if (iter->funcs->rewind) {
|
||||
iter->funcs->rewind(iter);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ZEND_METHOD(InternalIterator, __construct) {
|
||||
zend_throw_error(NULL, "Cannot manually construct InternalIterator");
|
||||
}
|
||||
|
||||
ZEND_METHOD(InternalIterator, current) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
|
||||
if (!intern) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zval *data = intern->iter->funcs->get_current_data(intern->iter);
|
||||
if (data) {
|
||||
ZVAL_COPY_DEREF(return_value, data);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_METHOD(InternalIterator, key) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
|
||||
if (!intern) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (intern->iter->funcs->get_current_key) {
|
||||
intern->iter->funcs->get_current_key(intern->iter, return_value);
|
||||
} else {
|
||||
RETURN_LONG(intern->iter->index);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_METHOD(InternalIterator, next) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
|
||||
if (!intern) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
intern->iter->funcs->move_forward(intern->iter);
|
||||
intern->iter->index++;
|
||||
}
|
||||
|
||||
ZEND_METHOD(InternalIterator, valid) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
|
||||
if (!intern) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (zend_internal_iterator_ensure_rewound(intern) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
RETURN_BOOL(intern->iter->funcs->valid(intern->iter) == SUCCESS);
|
||||
}
|
||||
|
||||
ZEND_METHOD(InternalIterator, rewind) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
zend_internal_iterator *intern = zend_internal_iterator_fetch(ZEND_THIS);
|
||||
if (!intern) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (!intern->iter->funcs->rewind) {
|
||||
/* Allow calling rewind() if no iteration has happened yet,
|
||||
* even if the iterator does not support rewinding. */
|
||||
if (intern->iter->index != 0) {
|
||||
zend_throw_error(NULL, "Iterator does not support rewinding");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
intern->iter->index = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
intern->iter->funcs->rewind(intern->iter);
|
||||
intern->iter->index = 0;
|
||||
}
|
||||
|
||||
/* {{{ zend_register_interfaces */
|
||||
ZEND_API void zend_register_interfaces(void)
|
||||
{
|
||||
zend_class_entry ce;
|
||||
|
||||
REGISTER_MAGIC_INTERFACE(traversable, Traversable);
|
||||
|
||||
REGISTER_MAGIC_INTERFACE(aggregate, IteratorAggregate);
|
||||
@ -454,7 +613,6 @@ ZEND_API void zend_register_interfaces(void)
|
||||
|
||||
REGISTER_MAGIC_INTERFACE(serializable, Serializable);
|
||||
|
||||
zend_class_entry ce;
|
||||
INIT_CLASS_ENTRY(ce, "ArrayAccess", class_ArrayAccess_methods);
|
||||
zend_ce_arrayaccess = zend_register_internal_interface(&ce);
|
||||
|
||||
@ -463,5 +621,17 @@ ZEND_API void zend_register_interfaces(void)
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "Stringable", class_Stringable_methods);
|
||||
zend_ce_stringable = zend_register_internal_interface(&ce);
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "InternalIterator", class_InternalIterator_methods);
|
||||
zend_ce_internal_iterator = zend_register_internal_class(&ce);
|
||||
zend_class_implements(zend_ce_internal_iterator, 1, zend_ce_iterator);
|
||||
zend_ce_internal_iterator->ce_flags |= ZEND_ACC_FINAL;
|
||||
zend_ce_internal_iterator->create_object = zend_internal_iterator_create;
|
||||
zend_ce_internal_iterator->serialize = zend_class_serialize_deny;
|
||||
zend_ce_internal_iterator->unserialize = zend_class_unserialize_deny;
|
||||
|
||||
memcpy(&zend_internal_iterator_handlers, zend_get_std_object_handlers(),
|
||||
sizeof(zend_object_handlers));
|
||||
zend_internal_iterator_handlers.free_obj = zend_internal_iterator_free;
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -78,6 +78,8 @@ ZEND_API int zend_user_unserialize(zval *object, zend_class_entry *ce, const uns
|
||||
ZEND_API int zend_class_serialize_deny(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data);
|
||||
ZEND_API int zend_class_unserialize_deny(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data);
|
||||
|
||||
ZEND_API int zend_create_internal_iterator_zval(zval *return_value, zval *obj);
|
||||
|
||||
END_EXTERN_C()
|
||||
|
||||
#endif /* ZEND_INTERFACES_H */
|
||||
|
@ -63,3 +63,20 @@ interface Stringable
|
||||
{
|
||||
public function __toString(): string;
|
||||
}
|
||||
|
||||
final class InternalIterator implements Iterator
|
||||
{
|
||||
private function __construct();
|
||||
|
||||
/** @return mixed */
|
||||
public function current();
|
||||
|
||||
/** @return mixed */
|
||||
public function key();
|
||||
|
||||
public function next(): void;
|
||||
|
||||
public function valid(): bool;
|
||||
|
||||
public function rewind(): void;
|
||||
}
|
||||
|
@ -38,7 +38,27 @@ ZEND_END_ARG_INFO()
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Stringable___toString, 0, 0, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_InternalIterator___construct arginfo_class_IteratorAggregate_getIterator
|
||||
|
||||
#define arginfo_class_InternalIterator_current arginfo_class_IteratorAggregate_getIterator
|
||||
|
||||
#define arginfo_class_InternalIterator_key arginfo_class_IteratorAggregate_getIterator
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_InternalIterator_next, 0, 0, IS_VOID, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_InternalIterator_valid, 0, 0, _IS_BOOL, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_InternalIterator_rewind arginfo_class_InternalIterator_next
|
||||
|
||||
|
||||
ZEND_METHOD(InternalIterator, __construct);
|
||||
ZEND_METHOD(InternalIterator, current);
|
||||
ZEND_METHOD(InternalIterator, key);
|
||||
ZEND_METHOD(InternalIterator, next);
|
||||
ZEND_METHOD(InternalIterator, valid);
|
||||
ZEND_METHOD(InternalIterator, rewind);
|
||||
|
||||
|
||||
static const zend_function_entry class_Traversable_methods[] = {
|
||||
@ -88,3 +108,14 @@ static const zend_function_entry class_Stringable_methods[] = {
|
||||
ZEND_ABSTRACT_ME_WITH_FLAGS(Stringable, __toString, arginfo_class_Stringable___toString, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
||||
static const zend_function_entry class_InternalIterator_methods[] = {
|
||||
ZEND_ME(InternalIterator, __construct, arginfo_class_InternalIterator___construct, ZEND_ACC_PRIVATE)
|
||||
ZEND_ME(InternalIterator, current, arginfo_class_InternalIterator_current, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(InternalIterator, key, arginfo_class_InternalIterator_key, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(InternalIterator, next, arginfo_class_InternalIterator_next, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(InternalIterator, valid, arginfo_class_InternalIterator_valid, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(InternalIterator, rewind, arginfo_class_InternalIterator_rewind, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
@ -576,6 +576,15 @@ ZEND_METHOD(WeakMap, count)
|
||||
RETURN_LONG(count);
|
||||
}
|
||||
|
||||
ZEND_METHOD(WeakMap, getIterator)
|
||||
{
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||
}
|
||||
|
||||
void zend_register_weakref_ce(void) /* {{{ */
|
||||
{
|
||||
zend_class_entry ce;
|
||||
@ -597,16 +606,14 @@ void zend_register_weakref_ce(void) /* {{{ */
|
||||
INIT_CLASS_ENTRY(ce, "WeakMap", class_WeakMap_methods);
|
||||
zend_ce_weakmap = zend_register_internal_class(&ce);
|
||||
zend_ce_weakmap->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES;
|
||||
zend_class_implements(
|
||||
zend_ce_weakmap, 3, zend_ce_arrayaccess, zend_ce_countable, zend_ce_aggregate);
|
||||
|
||||
zend_ce_weakmap->create_object = zend_weakmap_create_object;
|
||||
zend_ce_weakmap->get_iterator = zend_weakmap_get_iterator;
|
||||
zend_ce_weakmap->serialize = zend_class_serialize_deny;
|
||||
zend_ce_weakmap->unserialize = zend_class_unserialize_deny;
|
||||
|
||||
/* Must happen after get_iterator is assigned. */
|
||||
zend_class_implements(
|
||||
zend_ce_weakmap, 3, zend_ce_arrayaccess, zend_ce_countable, zend_ce_traversable);
|
||||
|
||||
memcpy(&zend_weakmap_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
|
||||
zend_weakmap_handlers.offset = XtOffsetOf(zend_weakmap, std);
|
||||
zend_weakmap_handlers.free_obj = zend_weakmap_free_obj;
|
||||
|
@ -11,7 +11,7 @@ final class WeakReference
|
||||
public function get(): ?object {}
|
||||
}
|
||||
|
||||
final class WeakMap implements ArrayAccess, Countable, Traversable
|
||||
final class WeakMap implements ArrayAccess, Countable, IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @param object $object
|
||||
@ -32,4 +32,6 @@ final class WeakMap implements ArrayAccess, Countable, Traversable
|
||||
public function offsetUnset($object): void {}
|
||||
|
||||
public function count(): int {}
|
||||
|
||||
public function getIterator(): Iterator {}
|
||||
}
|
||||
|
@ -30,6 +30,9 @@ ZEND_END_ARG_INFO()
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_WeakMap_count, 0, 0, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_WeakMap_getIterator, 0, 0, Iterator, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
|
||||
ZEND_METHOD(WeakReference, __construct);
|
||||
ZEND_METHOD(WeakReference, create);
|
||||
@ -39,6 +42,7 @@ ZEND_METHOD(WeakMap, offsetSet);
|
||||
ZEND_METHOD(WeakMap, offsetExists);
|
||||
ZEND_METHOD(WeakMap, offsetUnset);
|
||||
ZEND_METHOD(WeakMap, count);
|
||||
ZEND_METHOD(WeakMap, getIterator);
|
||||
|
||||
|
||||
static const zend_function_entry class_WeakReference_methods[] = {
|
||||
@ -55,5 +59,6 @@ static const zend_function_entry class_WeakMap_methods[] = {
|
||||
ZEND_ME(WeakMap, offsetExists, arginfo_class_WeakMap_offsetExists, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(WeakMap, offsetUnset, arginfo_class_WeakMap_offsetUnset, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(WeakMap, count, arginfo_class_WeakMap_count, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(WeakMap, getIterator, arginfo_class_WeakMap_getIterator, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
@ -1691,7 +1691,7 @@ static void date_register_classes(void) /* {{{ */
|
||||
ce_period.create_object = date_object_new_period;
|
||||
date_ce_period = zend_register_internal_class_ex(&ce_period, NULL);
|
||||
date_ce_period->get_iterator = date_object_period_get_iterator;
|
||||
zend_class_implements(date_ce_period, 1, zend_ce_traversable);
|
||||
zend_class_implements(date_ce_period, 1, zend_ce_aggregate);
|
||||
memcpy(&date_object_handlers_period, &std_object_handlers, sizeof(zend_object_handlers));
|
||||
date_object_handlers_period.offset = XtOffsetOf(php_period_obj, std);
|
||||
date_object_handlers_period.free_obj = date_object_free_storage_period;
|
||||
@ -4372,6 +4372,13 @@ PHP_METHOD(DatePeriod, getRecurrences)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_METHOD(DatePeriod, getIterator)
|
||||
{
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||
}
|
||||
|
||||
static int check_id_allowed(char *id, zend_long what) /* {{{ */
|
||||
{
|
||||
if ((what & PHP_DATE_TIMEZONE_GROUP_AFRICA) && strncasecmp(id, "Africa/", 7) == 0) return 1;
|
||||
|
@ -391,7 +391,7 @@ class DateInterval
|
||||
public static function __set_state(array $array) {}
|
||||
}
|
||||
|
||||
class DatePeriod implements Traversable
|
||||
class DatePeriod implements IteratorAggregate
|
||||
{
|
||||
/* Has an overloaded signature */
|
||||
public function __construct($start, $interval = UNKNOWN, $end = UNKNOWN) {}
|
||||
@ -412,4 +412,6 @@ class DatePeriod implements Traversable
|
||||
|
||||
/** @return DatePeriod */
|
||||
public static function __set_state(array $array) {}
|
||||
|
||||
public function getIterator(): Iterator {}
|
||||
}
|
||||
|
@ -423,6 +423,9 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_DatePeriod___set_state arginfo_class_DateTime___set_state
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_DatePeriod_getIterator, 0, 0, Iterator, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
|
||||
ZEND_FUNCTION(strtotime);
|
||||
ZEND_FUNCTION(date);
|
||||
@ -503,6 +506,7 @@ ZEND_METHOD(DatePeriod, getDateInterval);
|
||||
ZEND_METHOD(DatePeriod, getRecurrences);
|
||||
ZEND_METHOD(DatePeriod, __wakeup);
|
||||
ZEND_METHOD(DatePeriod, __set_state);
|
||||
ZEND_METHOD(DatePeriod, getIterator);
|
||||
|
||||
|
||||
static const zend_function_entry ext_functions[] = {
|
||||
@ -651,5 +655,6 @@ static const zend_function_entry class_DatePeriod_methods[] = {
|
||||
ZEND_ME(DatePeriod, getRecurrences, arginfo_class_DatePeriod_getRecurrences, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DatePeriod, __wakeup, arginfo_class_DatePeriod___wakeup, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DatePeriod, __set_state, arginfo_class_DatePeriod___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
ZEND_ME(DatePeriod, getIterator, arginfo_class_DatePeriod_getIterator, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
88
ext/date/tests/DatePeriod_IteratorAggregate.phpt
Normal file
88
ext/date/tests/DatePeriod_IteratorAggregate.phpt
Normal file
@ -0,0 +1,88 @@
|
||||
--TEST--
|
||||
DatePeriod can be used as an IteratorAggregate
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$period = new DatePeriod('R2/2012-07-01T00:00:00Z/P7D');
|
||||
foreach ($period as $i => $date) {
|
||||
echo "$i: ", $date->format('Y-m-d'), "\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
foreach ($period->getIterator() as $i => $date) {
|
||||
echo "$i: ", $date->format('Y-m-d'), "\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
$iter = $period->getIterator();
|
||||
for (; $iter->valid(); $iter->next()) {
|
||||
$i = $iter->key();
|
||||
$date = $iter->current();
|
||||
echo "$i: ", $date->format('Y-m-d'), "\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
$iter->rewind();
|
||||
for (; $iter->valid(); $iter->next()) {
|
||||
$i = $iter->key();
|
||||
$date = $iter->current();
|
||||
echo "$i: ", $date->format('Y-m-d'), "\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
foreach (new IteratorIterator($period) as $i => $date) {
|
||||
echo "$i: ", $date->format('Y-m-d'), "\n";
|
||||
}
|
||||
|
||||
// Extension that does not overwrite getIterator().
|
||||
class MyDatePeriod1 extends DatePeriod {
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
$period = new MyDatePeriod1('R2/2012-07-01T00:00:00Z/P7D');
|
||||
foreach ($period as $i => $date) {
|
||||
echo "$i: ", $date->format('Y-m-d'), "\n";
|
||||
}
|
||||
|
||||
// Extension that does overwrite getIterator().
|
||||
class MyDatePeriod2 extends DatePeriod {
|
||||
public function getIterator(): Iterator {
|
||||
return new ArrayIterator([1, 2, 3]);
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
$period = new MyDatePeriod2('R2/2012-07-01T00:00:00Z/P7D');
|
||||
foreach ($period as $i => $notDate) {
|
||||
echo "$i: $notDate\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
0: 2012-07-01
|
||||
1: 2012-07-08
|
||||
2: 2012-07-15
|
||||
|
||||
0: 2012-07-01
|
||||
1: 2012-07-08
|
||||
2: 2012-07-15
|
||||
|
||||
0: 2012-07-01
|
||||
1: 2012-07-08
|
||||
2: 2012-07-15
|
||||
|
||||
0: 2012-07-01
|
||||
1: 2012-07-08
|
||||
2: 2012-07-15
|
||||
|
||||
0: 2012-07-01
|
||||
1: 2012-07-08
|
||||
2: 2012-07-15
|
||||
|
||||
0: 2012-07-01
|
||||
1: 2012-07-08
|
||||
2: 2012-07-15
|
||||
|
||||
0: 1
|
||||
1: 2
|
||||
2: 3
|
@ -22,6 +22,7 @@
|
||||
#include "php.h"
|
||||
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
|
||||
#include "php_dom.h"
|
||||
#include "zend_interfaces.h"
|
||||
|
||||
/*
|
||||
* class DOMNamedNodeMap
|
||||
@ -266,4 +267,13 @@ PHP_METHOD(DOMNamedNodeMap, count)
|
||||
}
|
||||
/* }}} end dom_namednodemap_count */
|
||||
|
||||
PHP_METHOD(DOMNamedNodeMap, getIterator)
|
||||
{
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "php.h"
|
||||
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
|
||||
#include "php_dom.h"
|
||||
#include "zend_interfaces.h"
|
||||
|
||||
/*
|
||||
* class DOMNodeList
|
||||
@ -175,5 +176,13 @@ PHP_METHOD(DOMNodeList, item)
|
||||
}
|
||||
/* }}} end dom_nodelist_item */
|
||||
|
||||
ZEND_METHOD(DOMNodeList, getIterator)
|
||||
{
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -670,7 +670,7 @@ PHP_MINIT_FUNCTION(dom)
|
||||
ce.create_object = dom_nnodemap_objects_new;
|
||||
dom_nodelist_class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
dom_nodelist_class_entry->get_iterator = php_dom_get_iterator;
|
||||
zend_class_implements(dom_nodelist_class_entry, 2, zend_ce_traversable, zend_ce_countable);
|
||||
zend_class_implements(dom_nodelist_class_entry, 2, zend_ce_aggregate, zend_ce_countable);
|
||||
|
||||
zend_hash_init(&dom_nodelist_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
|
||||
dom_register_prop_handler(&dom_nodelist_prop_handlers, "length", sizeof("length")-1, dom_nodelist_length_read, NULL);
|
||||
@ -680,7 +680,7 @@ PHP_MINIT_FUNCTION(dom)
|
||||
ce.create_object = dom_nnodemap_objects_new;
|
||||
dom_namednodemap_class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
dom_namednodemap_class_entry->get_iterator = php_dom_get_iterator;
|
||||
zend_class_implements(dom_namednodemap_class_entry, 2, zend_ce_traversable, zend_ce_countable);
|
||||
zend_class_implements(dom_namednodemap_class_entry, 2, zend_ce_aggregate, zend_ce_countable);
|
||||
|
||||
zend_hash_init(&dom_namednodemap_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
|
||||
dom_register_prop_handler(&dom_namednodemap_prop_handlers, "length", sizeof("length")-1, dom_namednodemap_length_read, NULL);
|
||||
|
@ -123,12 +123,14 @@ class DOMDocumentFragment implements DOMParentNode
|
||||
public function prepend(...$nodes): void {}
|
||||
}
|
||||
|
||||
class DOMNodeList
|
||||
class DOMNodeList implements IteratorAggregate, Countable
|
||||
{
|
||||
/** @return int|false */
|
||||
public function count() {}
|
||||
|
||||
/** @return DOMNode|null */
|
||||
public function getIterator(): Iterator {}
|
||||
|
||||
/** @return ?DOMNode */
|
||||
public function item(int $index) {}
|
||||
}
|
||||
|
||||
@ -374,7 +376,7 @@ class DOMText
|
||||
public function splitText(int $offset) {}
|
||||
}
|
||||
|
||||
class DOMNamedNodeMap
|
||||
class DOMNamedNodeMap implements IteratorAggregate, Countable
|
||||
{
|
||||
/** @return DOMNode|null */
|
||||
public function getNamedItem(string $name) {}
|
||||
@ -387,6 +389,8 @@ class DOMNamedNodeMap
|
||||
|
||||
/** @return int|false */
|
||||
public function count() {}
|
||||
|
||||
public function getIterator(): Iterator {}
|
||||
}
|
||||
|
||||
class DOMEntity extends DOMNode
|
||||
|
@ -123,6 +123,9 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_DOMNodeList_count arginfo_class_DOMNode_getLineNo
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_DOMNodeList_getIterator, 0, 0, Iterator, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMNodeList_item, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@ -404,6 +407,8 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_DOMNamedNodeMap_count arginfo_class_DOMNode_getLineNo
|
||||
|
||||
#define arginfo_class_DOMNamedNodeMap_getIterator arginfo_class_DOMNodeList_getIterator
|
||||
|
||||
#define arginfo_class_DOMEntityReference___construct arginfo_class_DOMElement_getAttribute
|
||||
|
||||
#define arginfo_class_DOMProcessingInstruction___construct arginfo_class_DOMAttr___construct
|
||||
@ -470,6 +475,7 @@ ZEND_METHOD(DOMDocumentFragment, appendXML);
|
||||
ZEND_METHOD(DOMDocumentFragment, append);
|
||||
ZEND_METHOD(DOMDocumentFragment, prepend);
|
||||
ZEND_METHOD(DOMNodeList, count);
|
||||
ZEND_METHOD(DOMNodeList, getIterator);
|
||||
ZEND_METHOD(DOMNodeList, item);
|
||||
ZEND_METHOD(DOMCharacterData, appendData);
|
||||
ZEND_METHOD(DOMCharacterData, substringData);
|
||||
@ -564,6 +570,7 @@ ZEND_METHOD(DOMNamedNodeMap, getNamedItem);
|
||||
ZEND_METHOD(DOMNamedNodeMap, getNamedItemNS);
|
||||
ZEND_METHOD(DOMNamedNodeMap, item);
|
||||
ZEND_METHOD(DOMNamedNodeMap, count);
|
||||
ZEND_METHOD(DOMNamedNodeMap, getIterator);
|
||||
ZEND_METHOD(DOMEntityReference, __construct);
|
||||
ZEND_METHOD(DOMProcessingInstruction, __construct);
|
||||
#if defined(LIBXML_XPATH_ENABLED)
|
||||
@ -664,6 +671,7 @@ static const zend_function_entry class_DOMDocumentFragment_methods[] = {
|
||||
|
||||
static const zend_function_entry class_DOMNodeList_methods[] = {
|
||||
ZEND_ME(DOMNodeList, count, arginfo_class_DOMNodeList_count, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNodeList, getIterator, arginfo_class_DOMNodeList_getIterator, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNodeList, item, arginfo_class_DOMNodeList_item, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
@ -794,6 +802,7 @@ static const zend_function_entry class_DOMNamedNodeMap_methods[] = {
|
||||
ZEND_ME(DOMNamedNodeMap, getNamedItemNS, arginfo_class_DOMNamedNodeMap_getNamedItemNS, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNamedNodeMap, item, arginfo_class_DOMNamedNodeMap_item, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNamedNodeMap, count, arginfo_class_DOMNamedNodeMap_count, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(DOMNamedNodeMap, getIterator, arginfo_class_DOMNamedNodeMap_getIterator, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
/** @generate-function-entries */
|
||||
|
||||
class IntlBreakIterator implements Traversable
|
||||
class IntlBreakIterator implements IteratorAggregate
|
||||
{
|
||||
/** @return IntlBreakIterator|null */
|
||||
public static function createCharacterInstance(?string $locale = null) {}
|
||||
@ -65,6 +65,8 @@ class IntlBreakIterator implements Traversable
|
||||
|
||||
/** @return bool|null */
|
||||
public function setText(string $text) {}
|
||||
|
||||
public function getIterator(): Iterator {}
|
||||
}
|
||||
|
||||
class IntlRuleBasedBreakIterator extends IntlBreakIterator
|
||||
|
@ -56,6 +56,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlBreakIterator_setText, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, text, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_IntlBreakIterator_getIterator, 0, 0, Iterator, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlRuleBasedBreakIterator___construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, rules, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, areCompiled, _IS_BOOL, 0, "false")
|
||||
@ -95,6 +98,7 @@ ZEND_METHOD(IntlBreakIterator, next);
|
||||
ZEND_METHOD(IntlBreakIterator, preceding);
|
||||
ZEND_METHOD(IntlBreakIterator, previous);
|
||||
ZEND_METHOD(IntlBreakIterator, setText);
|
||||
ZEND_METHOD(IntlBreakIterator, getIterator);
|
||||
ZEND_METHOD(IntlRuleBasedBreakIterator, __construct);
|
||||
ZEND_METHOD(IntlRuleBasedBreakIterator, getBinaryRules);
|
||||
ZEND_METHOD(IntlRuleBasedBreakIterator, getRules);
|
||||
@ -126,6 +130,7 @@ static const zend_function_entry class_IntlBreakIterator_methods[] = {
|
||||
ZEND_ME(IntlBreakIterator, preceding, arginfo_class_IntlBreakIterator_preceding, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(IntlBreakIterator, previous, arginfo_class_IntlBreakIterator_previous, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(IntlBreakIterator, setText, arginfo_class_IntlBreakIterator_setText, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(IntlBreakIterator, getIterator, arginfo_class_IntlBreakIterator_getIterator, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
@ -236,8 +236,7 @@ U_CFUNC void breakiterator_register_BreakIterator_class(void)
|
||||
BreakIterator_handlers.get_debug_info = BreakIterator_get_debug_info;
|
||||
BreakIterator_handlers.free_obj = BreakIterator_objects_free;
|
||||
|
||||
zend_class_implements(BreakIterator_ce_ptr, 1,
|
||||
zend_ce_traversable);
|
||||
zend_class_implements(BreakIterator_ce_ptr, 1, zend_ce_aggregate);
|
||||
|
||||
zend_declare_class_constant_long(BreakIterator_ce_ptr,
|
||||
"DONE", sizeof("DONE") - 1, BreakIterator::DONE );
|
||||
|
@ -27,6 +27,7 @@ extern "C" {
|
||||
#include "breakiterator_class.h"
|
||||
#include "../locale/locale.h"
|
||||
#include <zend_exceptions.h>
|
||||
#include <zend_interfaces.h>
|
||||
}
|
||||
|
||||
using PHP::CodePointBreakIterator;
|
||||
@ -399,3 +400,12 @@ U_CFUNC PHP_METHOD(IntlBreakIterator, getErrorMessage)
|
||||
message = intl_error_get_message(BREAKITER_ERROR_P(bio));
|
||||
RETURN_STR(message);
|
||||
}
|
||||
|
||||
U_CFUNC PHP_METHOD(IntlBreakIterator, getIterator)
|
||||
{
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
/** @generate-function-entries */
|
||||
|
||||
class ResourceBundle implements Traversable
|
||||
class ResourceBundle implements IteratorAggregate, Countable
|
||||
{
|
||||
public function __construct(?string $locale, ?string $bundlename, bool $fallback = true) {}
|
||||
|
||||
@ -42,4 +42,6 @@ class ResourceBundle implements Traversable
|
||||
* @alias resourcebundle_get_error_message
|
||||
*/
|
||||
public function getErrorMessage() {}
|
||||
|
||||
public function getIterator(): Iterator {}
|
||||
}
|
||||
|
@ -25,6 +25,9 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_ResourceBundle_getErrorMessage arginfo_class_ResourceBundle_count
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ResourceBundle_getIterator, 0, 0, Iterator, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
|
||||
ZEND_METHOD(ResourceBundle, __construct);
|
||||
ZEND_FUNCTION(resourcebundle_create);
|
||||
@ -33,6 +36,7 @@ ZEND_FUNCTION(resourcebundle_count);
|
||||
ZEND_FUNCTION(resourcebundle_locales);
|
||||
ZEND_FUNCTION(resourcebundle_get_error_code);
|
||||
ZEND_FUNCTION(resourcebundle_get_error_message);
|
||||
ZEND_METHOD(ResourceBundle, getIterator);
|
||||
|
||||
|
||||
static const zend_function_entry class_ResourceBundle_methods[] = {
|
||||
@ -43,5 +47,6 @@ static const zend_function_entry class_ResourceBundle_methods[] = {
|
||||
ZEND_ME_MAPPING(getLocales, resourcebundle_locales, arginfo_class_ResourceBundle_getLocales, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
ZEND_ME_MAPPING(getErrorCode, resourcebundle_get_error_code, arginfo_class_ResourceBundle_getErrorCode, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME_MAPPING(getErrorMessage, resourcebundle_get_error_message, arginfo_class_ResourceBundle_getErrorMessage, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(ResourceBundle, getIterator, arginfo_class_ResourceBundle_getIterator, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
@ -368,6 +368,14 @@ PHP_FUNCTION( resourcebundle_get_error_message )
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_METHOD(ResourceBundle, getIterator) {
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||
}
|
||||
|
||||
/* {{{ resourcebundle_register_class
|
||||
* Initialize 'ResourceBundle' class
|
||||
*/
|
||||
@ -389,6 +397,6 @@ void resourcebundle_register_class( void )
|
||||
ResourceBundle_object_handlers.read_dimension = resourcebundle_array_get;
|
||||
ResourceBundle_object_handlers.count_elements = resourcebundle_array_count;
|
||||
|
||||
zend_class_implements(ResourceBundle_ce_ptr, 2, zend_ce_traversable, zend_ce_countable);
|
||||
zend_class_implements(ResourceBundle_ce_ptr, 2, zend_ce_aggregate, zend_ce_countable);
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -636,7 +636,7 @@ PHP_MINIT_FUNCTION(mysqli)
|
||||
zend_declare_property_null(ce, "num_rows", sizeof("num_rows") - 1, ZEND_ACC_PUBLIC);
|
||||
zend_declare_property_null(ce, "type", sizeof("type") - 1, ZEND_ACC_PUBLIC);
|
||||
mysqli_result_class_entry->get_iterator = php_mysqli_result_get_iterator;
|
||||
zend_class_implements(mysqli_result_class_entry, 1, zend_ce_traversable);
|
||||
zend_class_implements(mysqli_result_class_entry, 1, zend_ce_aggregate);
|
||||
zend_hash_add_ptr(&classes, ce->name, &mysqli_result_properties);
|
||||
|
||||
REGISTER_MYSQLI_CLASS_ENTRY("mysqli_stmt", mysqli_stmt_class_entry, class_mysqli_stmt_methods);
|
||||
@ -1087,6 +1087,15 @@ PHP_FUNCTION(mysqli_result_construct)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_METHOD(mysqli_result, getIterator)
|
||||
{
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||
}
|
||||
|
||||
/* {{{ php_mysqli_fetch_into_hash_aux
|
||||
*/
|
||||
void php_mysqli_fetch_into_hash_aux(zval *return_value, MYSQL_RES * result, zend_long fetchtype)
|
||||
|
@ -300,7 +300,7 @@ class mysqli
|
||||
public function refresh(int $options) {}
|
||||
}
|
||||
|
||||
class mysqli_result
|
||||
class mysqli_result implements IteratorAggregate
|
||||
{
|
||||
/** @alias mysqli_result_construct */
|
||||
public function __construct(object $mysqli_link, int $resmode = MYSQLI_STORE_RESULT) {}
|
||||
@ -384,6 +384,8 @@ class mysqli_result
|
||||
* @alias mysqli_free_result
|
||||
*/
|
||||
public function free_result() {}
|
||||
|
||||
public function getIterator(): Iterator;
|
||||
}
|
||||
|
||||
class mysqli_stmt
|
||||
|
@ -618,6 +618,9 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_mysqli_result_free_result arginfo_class_mysqli_character_set_name
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_mysqli_result_getIterator, 0, 0, Iterator, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_stmt___construct, 0, 0, 1)
|
||||
ZEND_ARG_OBJ_INFO(0, mysqli_link, mysqli, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, statement, IS_STRING, 1, "null")
|
||||
@ -803,6 +806,7 @@ ZEND_FUNCTION(mysqli_result_construct);
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
ZEND_FUNCTION(mysqli_fetch_all);
|
||||
#endif
|
||||
ZEND_METHOD(mysqli_result, getIterator);
|
||||
ZEND_FUNCTION(mysqli_stmt_construct);
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
ZEND_FUNCTION(mysqli_stmt_more_results);
|
||||
@ -1002,6 +1006,7 @@ static const zend_function_entry class_mysqli_result_methods[] = {
|
||||
ZEND_ME_MAPPING(fetch_row, mysqli_fetch_row, arginfo_class_mysqli_result_fetch_row, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME_MAPPING(field_seek, mysqli_field_seek, arginfo_class_mysqli_result_field_seek, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME_MAPPING(free_result, mysqli_free_result, arginfo_class_mysqli_result_free_result, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(mysqli_result, getIterator, arginfo_class_mysqli_result_getIterator, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
@ -38,6 +38,7 @@ require_once('skipifconnectfailure.inc');
|
||||
'field_seek' => true,
|
||||
'free' => true,
|
||||
'free_result' => true,
|
||||
'getIterator' => true,
|
||||
);
|
||||
if ($IS_MYSQLND)
|
||||
$expected_methods['fetch_all'] = true;
|
||||
|
@ -2072,6 +2072,15 @@ PHP_METHOD(PDOStatement, debugDumpParams)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_METHOD(PDOStatement, getIterator)
|
||||
{
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||
}
|
||||
|
||||
/* {{{ overloaded handlers for PDOStatement class */
|
||||
static zval *dbstmt_prop_write(zend_object *object, zend_string *name, zval *value, void **cache_slot)
|
||||
{
|
||||
@ -2583,7 +2592,7 @@ void pdo_stmt_init(void)
|
||||
pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
|
||||
pdo_dbstmt_ce->serialize = zend_class_serialize_deny;
|
||||
pdo_dbstmt_ce->unserialize = zend_class_unserialize_deny;
|
||||
zend_class_implements(pdo_dbstmt_ce, 1, zend_ce_traversable);
|
||||
zend_class_implements(pdo_dbstmt_ce, 1, zend_ce_aggregate);
|
||||
zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC);
|
||||
|
||||
memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
/** @generate-function-entries */
|
||||
|
||||
class PDOStatement implements Traversable
|
||||
class PDOStatement implements IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @param mixed $driverdata
|
||||
@ -76,6 +76,8 @@ class PDOStatement implements Traversable
|
||||
|
||||
/** @return bool */
|
||||
public function setFetchMode(int $mode, $param1 = UNKNOWN, $param2 = UNKNOWN) {}
|
||||
|
||||
public function getIterator(): Iterator {}
|
||||
}
|
||||
|
||||
final class PDORow
|
||||
|
@ -82,6 +82,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDOStatement_setFetchMode, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, param2)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_PDOStatement_getIterator, 0, 0, Iterator, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
|
||||
ZEND_METHOD(PDOStatement, bindColumn);
|
||||
ZEND_METHOD(PDOStatement, bindParam);
|
||||
@ -102,6 +105,7 @@ ZEND_METHOD(PDOStatement, nextRowset);
|
||||
ZEND_METHOD(PDOStatement, rowCount);
|
||||
ZEND_METHOD(PDOStatement, setAttribute);
|
||||
ZEND_METHOD(PDOStatement, setFetchMode);
|
||||
ZEND_METHOD(PDOStatement, getIterator);
|
||||
|
||||
|
||||
static const zend_function_entry class_PDOStatement_methods[] = {
|
||||
@ -124,6 +128,7 @@ static const zend_function_entry class_PDOStatement_methods[] = {
|
||||
ZEND_ME(PDOStatement, rowCount, arginfo_class_PDOStatement_rowCount, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(PDOStatement, setAttribute, arginfo_class_PDOStatement_setAttribute, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(PDOStatement, setFetchMode, arginfo_class_PDOStatement_setFetchMode, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(PDOStatement, getIterator, arginfo_class_PDOStatement_getIterator, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
@ -51,7 +51,7 @@ class PDOStatementAggregate extends PDOStatement implements IteratorAggregate
|
||||
/* default fetch mode is BOTH, so we see if the ctor can overwrite that */
|
||||
}
|
||||
|
||||
function getIterator()
|
||||
function getIterator(): Iterator
|
||||
{
|
||||
echo __METHOD__ . "\n";
|
||||
$this->execute();
|
||||
|
Loading…
Reference in New Issue
Block a user