ext/spl: Throw TypeError when overloaded SplObjectStorage::getHash() method does not return a string

This commit is contained in:
Gina Peter Banyard 2024-03-10 16:25:15 +00:00
parent 610c7a07b1
commit a648365fc0
No known key found for this signature in database
GPG key ID: 3306078E3194AEBD
2 changed files with 47 additions and 42 deletions

View file

@ -87,20 +87,21 @@ static zend_result spl_object_storage_get_hash(zend_hash_key *key, spl_SplObject
zval param; zval param;
zval rv; zval rv;
ZVAL_OBJ(&param, obj); ZVAL_OBJ(&param, obj);
zend_call_method_with_1_params( zend_call_method_with_1_params(&intern->std, intern->std.ce, &intern->fptr_get_hash, "getHash", &rv, &param);
&intern->std, intern->std.ce, &intern->fptr_get_hash, "getHash", &rv, &param); if (UNEXPECTED(Z_ISUNDEF(rv))) {
if (!Z_ISUNDEF(rv)) { /* An exception has occurred */
if (Z_TYPE(rv) == IS_STRING) { return FAILURE;
key->key = Z_STR(rv); } else {
return SUCCESS; /* TODO PHP 9: Remove this as this will be enforced from the return type */
} else { if (UNEXPECTED(Z_TYPE(rv) != IS_STRING)) {
zend_throw_exception(spl_ce_RuntimeException, "Hash needs to be a string", 0); zend_type_error("%s::getHash(): Return value must be of type string, %s returned",
ZSTR_VAL(intern->std.ce->name), zend_zval_value_name(&rv));
zval_ptr_dtor(&rv); zval_ptr_dtor(&rv);
return FAILURE; return FAILURE;
} else {
key->key = Z_STR(rv);
return SUCCESS;
} }
} else {
return FAILURE;
} }
} else { } else {
key->key = NULL; key->key = NULL;

View file

@ -1,27 +1,15 @@
--TEST-- --TEST--
SplObjectStorage::getHash implementation SplObjectStorage::getHash() implementation
--FILE-- --FILE--
<?php <?php
$s = new SplObjectStorage();
$o1 = new Stdclass;
$o2 = new Stdclass;
$s[$o1] = "some_value\n";
echo $s->offsetGet($o1);
class MySplObjectStorage extends SplObjectStorage { class MySplObjectStorage1 extends SplObjectStorage {
#[ReturnTypeWillChange] #[ReturnTypeWillChange]
public function getHash($obj) { public function getHash($obj) {
return 2; return 2;
} }
} }
try {
$s1 = new MySplObjectStorage;
$s1[$o1] = "foo";
} catch(Exception $e) {
echo "caught 1\n";
}
class MySplObjectStorage2 extends SplObjectStorage { class MySplObjectStorage2 extends SplObjectStorage {
public function getHash($obj): string { public function getHash($obj): string {
throw new Exception("foo"); throw new Exception("foo");
@ -29,31 +17,47 @@ class MySplObjectStorage2 extends SplObjectStorage {
} }
} }
try {
$s2 = new MySplObjectStorage2;
$s2[$o2] = "foo";
} catch(Exception $e) {
echo "caught 2\n";
}
class MySplObjectStorage3 extends SplObjectStorage { class MySplObjectStorage3 extends SplObjectStorage {
public function getHash($obj): string { public function getHash($obj): string {
return "asd"; return "asd";
} }
} }
$s3 = new MySplObjectStorage3; $s = new SplObjectStorage();
$s3[$o1] = $o1; $o1 = new stdClass();
var_dump($s3[$o1]); $o2 = new stdClass();
$s3[$o2] = $o2;
var_dump($s3[$o1] === $s3[$o2]); $instances = [
new SplObjectStorage(),
new MySplObjectStorage1(),
new MySplObjectStorage2(),
new MySplObjectStorage3(),
];
foreach ($instances as $instance) {
echo 'Instance as ', $instance::class, PHP_EOL;
try {
$instance[$o1] = 'foo';
var_dump($instance->offsetGet($o1));
var_dump($instance[$o1]);
$instance[$o2] = $o2;
var_dump($instance[$o1] === $instance[$o2]);
} catch(Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
}
?> ?>
--EXPECT-- --EXPECT--
some_value Instance as SplObjectStorage
caught 1 string(3) "foo"
caught 2 string(3) "foo"
object(stdClass)#2 (0) { bool(false)
} Instance as MySplObjectStorage1
TypeError: MySplObjectStorage1::getHash(): Return value must be of type string, int returned
Instance as MySplObjectStorage2
Exception: foo
Instance as MySplObjectStorage3
string(3) "foo"
string(3) "foo"
bool(true) bool(true)