Skip to content

Commit a648365

Browse files
committed
ext/spl: Throw TypeError when overloaded SplObjectStorage::getHash() method does not return a string
1 parent 610c7a0 commit a648365

File tree

2 files changed

+48
-43
lines changed

2 files changed

+48
-43
lines changed

ext/spl/spl_observer.c

+12-11
Original file line numberDiff line numberDiff line change
@@ -87,20 +87,21 @@ static zend_result spl_object_storage_get_hash(zend_hash_key *key, spl_SplObject
8787
zval param;
8888
zval rv;
8989
ZVAL_OBJ(&param, obj);
90-
zend_call_method_with_1_params(
91-
&intern->std, intern->std.ce, &intern->fptr_get_hash, "getHash", &rv, &param);
92-
if (!Z_ISUNDEF(rv)) {
93-
if (Z_TYPE(rv) == IS_STRING) {
94-
key->key = Z_STR(rv);
95-
return SUCCESS;
96-
} else {
97-
zend_throw_exception(spl_ce_RuntimeException, "Hash needs to be a string", 0);
98-
90+
zend_call_method_with_1_params(&intern->std, intern->std.ce, &intern->fptr_get_hash, "getHash", &rv, &param);
91+
if (UNEXPECTED(Z_ISUNDEF(rv))) {
92+
/* An exception has occurred */
93+
return FAILURE;
94+
} else {
95+
/* TODO PHP 9: Remove this as this will be enforced from the return type */
96+
if (UNEXPECTED(Z_TYPE(rv) != IS_STRING)) {
97+
zend_type_error("%s::getHash(): Return value must be of type string, %s returned",
98+
ZSTR_VAL(intern->std.ce->name), zend_zval_value_name(&rv));
9999
zval_ptr_dtor(&rv);
100100
return FAILURE;
101+
} else {
102+
key->key = Z_STR(rv);
103+
return SUCCESS;
101104
}
102-
} else {
103-
return FAILURE;
104105
}
105106
} else {
106107
key->key = NULL;
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,63 @@
11
--TEST--
2-
SplObjectStorage::getHash implementation
2+
SplObjectStorage::getHash() implementation
33
--FILE--
44
<?php
5-
$s = new SplObjectStorage();
6-
$o1 = new Stdclass;
7-
$o2 = new Stdclass;
8-
$s[$o1] = "some_value\n";
9-
echo $s->offsetGet($o1);
105

11-
class MySplObjectStorage extends SplObjectStorage {
6+
class MySplObjectStorage1 extends SplObjectStorage {
127
#[ReturnTypeWillChange]
138
public function getHash($obj) {
149
return 2;
1510
}
1611
}
1712

18-
try {
19-
$s1 = new MySplObjectStorage;
20-
$s1[$o1] = "foo";
21-
} catch(Exception $e) {
22-
echo "caught 1\n";
23-
}
24-
2513
class MySplObjectStorage2 extends SplObjectStorage {
2614
public function getHash($obj): string {
2715
throw new Exception("foo");
2816
return "asd";
2917
}
3018
}
3119

32-
try {
33-
$s2 = new MySplObjectStorage2;
34-
$s2[$o2] = "foo";
35-
} catch(Exception $e) {
36-
echo "caught 2\n";
37-
}
38-
3920
class MySplObjectStorage3 extends SplObjectStorage {
4021
public function getHash($obj): string {
4122
return "asd";
4223
}
4324
}
4425

45-
$s3 = new MySplObjectStorage3;
46-
$s3[$o1] = $o1;
47-
var_dump($s3[$o1]);
48-
$s3[$o2] = $o2;
49-
50-
var_dump($s3[$o1] === $s3[$o2]);
26+
$s = new SplObjectStorage();
27+
$o1 = new stdClass();
28+
$o2 = new stdClass();
29+
30+
$instances = [
31+
new SplObjectStorage(),
32+
new MySplObjectStorage1(),
33+
new MySplObjectStorage2(),
34+
new MySplObjectStorage3(),
35+
];
36+
37+
foreach ($instances as $instance) {
38+
echo 'Instance as ', $instance::class, PHP_EOL;
39+
try {
40+
$instance[$o1] = 'foo';
41+
var_dump($instance->offsetGet($o1));
42+
var_dump($instance[$o1]);
43+
$instance[$o2] = $o2;
44+
var_dump($instance[$o1] === $instance[$o2]);
45+
} catch(Throwable $e) {
46+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
47+
}
48+
}
5149

5250
?>
5351
--EXPECT--
54-
some_value
55-
caught 1
56-
caught 2
57-
object(stdClass)#2 (0) {
58-
}
52+
Instance as SplObjectStorage
53+
string(3) "foo"
54+
string(3) "foo"
55+
bool(false)
56+
Instance as MySplObjectStorage1
57+
TypeError: MySplObjectStorage1::getHash(): Return value must be of type string, int returned
58+
Instance as MySplObjectStorage2
59+
Exception: foo
60+
Instance as MySplObjectStorage3
61+
string(3) "foo"
62+
string(3) "foo"
5963
bool(true)

0 commit comments

Comments
 (0)