mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Implement SeekableIterator for SplObjectStorage (#13665)
This commit is contained in:
3
NEWS
3
NEWS
@@ -239,6 +239,9 @@ PHP NEWS
|
||||
. Add support for AEGIS-128L and AEGIS-256 (jedisct1)
|
||||
. Enable AES-GCM on aarch64 with the ARM crypto extensions (jedisct1)
|
||||
|
||||
- SPL:
|
||||
. Implement SeekableIterator for SplObjectStorage. (nielsdos)
|
||||
|
||||
- Standard:
|
||||
. Implement GH-12188 (Indication for the int size in phpinfo()). (timwolla)
|
||||
. Partly fix GH-12143 (Incorrect round() result for 0.49999999999999994).
|
||||
|
||||
@@ -504,6 +504,10 @@ PHP 8.4 UPGRADE NOTES
|
||||
. sodium_crypto_aead_aes256gcm_*() functions are now enabled on aarch64 CPUs
|
||||
with the ARM cryptographic extensions.
|
||||
|
||||
- SPL:
|
||||
. Added seek() method to SplObjectStorage, now it implements
|
||||
SeekableIterator.
|
||||
|
||||
- Standard:
|
||||
. Added the http_get_last_response_headers() and
|
||||
http_clear_last_response_headers() that allows retrieving the same content
|
||||
|
||||
@@ -758,6 +758,49 @@ PHP_METHOD(SplObjectStorage, next)
|
||||
intern->index++;
|
||||
} /* }}} */
|
||||
|
||||
/* {{{ Seek to position. */
|
||||
PHP_METHOD(SplObjectStorage, seek)
|
||||
{
|
||||
zend_long position;
|
||||
spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS);
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &position) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (position < 0 || position >= zend_hash_num_elements(&intern->storage)) {
|
||||
zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position " ZEND_LONG_FMT " is out of range", position);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (position == 0) {
|
||||
/* fast path */
|
||||
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
|
||||
intern->index = 0;
|
||||
} else if (position > intern->index) {
|
||||
/* unlike the optimization below, it's not cheap to go to the end */
|
||||
do {
|
||||
zend_hash_move_forward_ex(&intern->storage, &intern->pos);
|
||||
intern->index++;
|
||||
} while (position > intern->index);
|
||||
} else if (position < intern->index) {
|
||||
/* optimization: check if it's more profitable to reset and do a forwards seek instead, it's cheap to reset */
|
||||
if (intern->index - position > position) {
|
||||
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
|
||||
intern->index = 0;
|
||||
do {
|
||||
zend_hash_move_forward_ex(&intern->storage, &intern->pos);
|
||||
intern->index++;
|
||||
} while (position > intern->index);
|
||||
} else {
|
||||
do {
|
||||
zend_hash_move_backwards_ex(&intern->storage, &intern->pos);
|
||||
intern->index--;
|
||||
} while (position < intern->index);
|
||||
}
|
||||
}
|
||||
} /* }}} */
|
||||
|
||||
/* {{{ Serializes storage */
|
||||
PHP_METHOD(SplObjectStorage, serialize)
|
||||
{
|
||||
@@ -1326,7 +1369,7 @@ PHP_MINIT_FUNCTION(spl_observer)
|
||||
spl_ce_SplObserver = register_class_SplObserver();
|
||||
spl_ce_SplSubject = register_class_SplSubject();
|
||||
|
||||
spl_ce_SplObjectStorage = register_class_SplObjectStorage(zend_ce_countable, zend_ce_iterator, zend_ce_serializable, zend_ce_arrayaccess);
|
||||
spl_ce_SplObjectStorage = register_class_SplObjectStorage(zend_ce_countable, spl_ce_SeekableIterator, zend_ce_serializable, zend_ce_arrayaccess);
|
||||
spl_ce_SplObjectStorage->create_object = spl_SplObjectStorage_new;
|
||||
spl_ce_SplObjectStorage->default_object_handlers = &spl_handler_SplObjectStorage;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ interface SplSubject
|
||||
public function notify(): void;
|
||||
}
|
||||
|
||||
class SplObjectStorage implements Countable, Iterator, Serializable, ArrayAccess
|
||||
class SplObjectStorage implements Countable, SeekableIterator, Serializable, ArrayAccess
|
||||
{
|
||||
/** @tentative-return-type */
|
||||
public function attach(object $object, mixed $info = null): void {}
|
||||
@@ -64,6 +64,8 @@ class SplObjectStorage implements Countable, Iterator, Serializable, ArrayAccess
|
||||
/** @tentative-return-type */
|
||||
public function next(): void {}
|
||||
|
||||
public function seek(int $offset): void {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
public function unserialize(string $data): void {}
|
||||
|
||||
|
||||
12
ext/spl/spl_observer_arginfo.h
generated
12
ext/spl/spl_observer_arginfo.h
generated
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 1fc23a91e7531eeb73729d4ad44addf0190c3a62 */
|
||||
* Stub hash: a846c9dd240b6f0666cd5e805abfacabe360cf4c */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplObserver_update, 0, 1, IS_VOID, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, subject, SplSubject, 0)
|
||||
@@ -59,6 +59,10 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_SplObjectStorage_next arginfo_class_SplSubject_notify
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SplObjectStorage_seek, 0, 1, IS_VOID, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplObjectStorage_unserialize, 0, 1, IS_VOID, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -147,6 +151,7 @@ ZEND_METHOD(SplObjectStorage, valid);
|
||||
ZEND_METHOD(SplObjectStorage, key);
|
||||
ZEND_METHOD(SplObjectStorage, current);
|
||||
ZEND_METHOD(SplObjectStorage, next);
|
||||
ZEND_METHOD(SplObjectStorage, seek);
|
||||
ZEND_METHOD(SplObjectStorage, unserialize);
|
||||
ZEND_METHOD(SplObjectStorage, serialize);
|
||||
ZEND_METHOD(SplObjectStorage, offsetGet);
|
||||
@@ -194,6 +199,7 @@ static const zend_function_entry class_SplObjectStorage_methods[] = {
|
||||
ZEND_ME(SplObjectStorage, key, arginfo_class_SplObjectStorage_key, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplObjectStorage, current, arginfo_class_SplObjectStorage_current, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplObjectStorage, next, arginfo_class_SplObjectStorage_next, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplObjectStorage, seek, arginfo_class_SplObjectStorage_seek, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplObjectStorage, unserialize, arginfo_class_SplObjectStorage_unserialize, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplObjectStorage, serialize, arginfo_class_SplObjectStorage_serialize, ZEND_ACC_PUBLIC)
|
||||
ZEND_RAW_FENTRY("offsetExists", zim_SplObjectStorage_contains, arginfo_class_SplObjectStorage_offsetExists, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
@@ -244,13 +250,13 @@ static zend_class_entry *register_class_SplSubject(void)
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class_SplObjectStorage(zend_class_entry *class_entry_Countable, zend_class_entry *class_entry_Iterator, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_ArrayAccess)
|
||||
static zend_class_entry *register_class_SplObjectStorage(zend_class_entry *class_entry_Countable, zend_class_entry *class_entry_SeekableIterator, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_ArrayAccess)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "SplObjectStorage", class_SplObjectStorage_methods);
|
||||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
zend_class_implements(class_entry, 4, class_entry_Countable, class_entry_Iterator, class_entry_Serializable, class_entry_ArrayAccess);
|
||||
zend_class_implements(class_entry, 4, class_entry_Countable, class_entry_SeekableIterator, class_entry_Serializable, class_entry_ArrayAccess);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
139
ext/spl/tests/SplObjectStorage_seek.phpt
Normal file
139
ext/spl/tests/SplObjectStorage_seek.phpt
Normal file
@@ -0,0 +1,139 @@
|
||||
--TEST--
|
||||
SplObjectStorage::seek() basic functionality
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public function __construct(public string $marker) {}
|
||||
}
|
||||
|
||||
$a = new Test("a");
|
||||
$b = new Test("b");
|
||||
$c = new Test("c");
|
||||
$d = new Test("d");
|
||||
$e = new Test("e");
|
||||
|
||||
$storage = new SplObjectStorage();
|
||||
$storage[$a] = 1;
|
||||
$storage[$b] = 2;
|
||||
$storage[$c] = 3;
|
||||
$storage[$d] = 4;
|
||||
$storage[$e] = 5;
|
||||
|
||||
echo "--- Error cases ---\n";
|
||||
|
||||
try {
|
||||
$storage->seek(-1);
|
||||
} catch (OutOfBoundsException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
$storage->seek(5);
|
||||
} catch (OutOfBoundsException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
var_dump($storage->key());
|
||||
var_dump($storage->current());
|
||||
|
||||
echo "--- Normal cases ---\n";
|
||||
|
||||
$storage->seek(2);
|
||||
var_dump($storage->key());
|
||||
var_dump($storage->current());
|
||||
|
||||
$storage->seek(1);
|
||||
var_dump($storage->key());
|
||||
var_dump($storage->current());
|
||||
|
||||
$storage->seek(4);
|
||||
var_dump($storage->key());
|
||||
var_dump($storage->current());
|
||||
|
||||
$storage->seek(0);
|
||||
var_dump($storage->key());
|
||||
var_dump($storage->current());
|
||||
|
||||
$storage->seek(3);
|
||||
var_dump($storage->key());
|
||||
var_dump($storage->current());
|
||||
|
||||
$storage->seek(3);
|
||||
var_dump($storage->key());
|
||||
var_dump($storage->current());
|
||||
|
||||
echo "--- With holes cases ---\n";
|
||||
|
||||
$storage->detach($b);
|
||||
$storage->detach($d);
|
||||
|
||||
foreach (range(0, 2) as $index) {
|
||||
$storage->seek($index);
|
||||
var_dump($storage->key());
|
||||
var_dump($storage->current());
|
||||
}
|
||||
|
||||
try {
|
||||
$storage->seek(3);
|
||||
} catch (OutOfBoundsException $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
--- Error cases ---
|
||||
Seek position -1 is out of range
|
||||
Seek position 5 is out of range
|
||||
int(0)
|
||||
object(Test)#1 (1) {
|
||||
["marker"]=>
|
||||
string(1) "a"
|
||||
}
|
||||
--- Normal cases ---
|
||||
int(2)
|
||||
object(Test)#3 (1) {
|
||||
["marker"]=>
|
||||
string(1) "c"
|
||||
}
|
||||
int(1)
|
||||
object(Test)#2 (1) {
|
||||
["marker"]=>
|
||||
string(1) "b"
|
||||
}
|
||||
int(4)
|
||||
object(Test)#5 (1) {
|
||||
["marker"]=>
|
||||
string(1) "e"
|
||||
}
|
||||
int(0)
|
||||
object(Test)#1 (1) {
|
||||
["marker"]=>
|
||||
string(1) "a"
|
||||
}
|
||||
int(3)
|
||||
object(Test)#4 (1) {
|
||||
["marker"]=>
|
||||
string(1) "d"
|
||||
}
|
||||
int(3)
|
||||
object(Test)#4 (1) {
|
||||
["marker"]=>
|
||||
string(1) "d"
|
||||
}
|
||||
--- With holes cases ---
|
||||
int(0)
|
||||
object(Test)#1 (1) {
|
||||
["marker"]=>
|
||||
string(1) "a"
|
||||
}
|
||||
int(1)
|
||||
object(Test)#3 (1) {
|
||||
["marker"]=>
|
||||
string(1) "c"
|
||||
}
|
||||
int(2)
|
||||
object(Test)#5 (1) {
|
||||
["marker"]=>
|
||||
string(1) "e"
|
||||
}
|
||||
Seek position 3 is out of range
|
||||
Reference in New Issue
Block a user