Skip to content

Commit 06995f5

Browse files
[7.2] Add polyfill for spl_object_id()
1 parent ce1fc5b commit 06995f5

File tree

5 files changed

+57
-1
lines changed

5 files changed

+57
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Polyfills are provided for:
2929
- the `is_iterable` function introduced in PHP 7.1;
3030
- a `Binary` utility class to be used when compatibility with
3131
`mbstring.func_overload` is required;
32-
- the `stream_isatty` function introduced in PHP 7.2;
32+
- the `spl_object_id` and `stream_isatty` functions introduced in PHP 7.2;
3333
- the `sapi_windows_vt100_support` function (Windows only) introduced in PHP 7.2;
3434
- the `PHP_OS_FAMILY` constant introduced in PHP 7.2.
3535

src/Php72/Php72.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
*/
2020
final class Php72
2121
{
22+
private static $hashMask;
23+
2224
public static function utf8_encode($s)
2325
{
2426
$s .= $s;
@@ -80,4 +82,38 @@ public static function php_os_family()
8082

8183
return isset($map[PHP_OS]) ? $map[PHP_OS] : 'Unknown';
8284
}
85+
86+
public static function spl_object_id($object)
87+
{
88+
if (null === self::$hashMask) {
89+
self::initHashMask();
90+
}
91+
if (null === $hash = spl_object_hash($object)) {
92+
return;
93+
}
94+
95+
return self::$hashMask ^ hexdec(substr($hash, 16 - \PHP_INT_SIZE, \PHP_INT_SIZE));
96+
}
97+
98+
private static function initHashMask()
99+
{
100+
$obj = (object) array();
101+
self::$hashMask = -1;
102+
103+
// check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below
104+
$obFuncs = array('ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush');
105+
foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) {
106+
if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && in_array($frame['function'], $obFuncs)) {
107+
$frame['line'] = 0;
108+
break;
109+
}
110+
}
111+
if (!empty($frame['line'])) {
112+
ob_start();
113+
debug_zval_dump($obj);
114+
self::$hashMask = (int) substr(ob_get_clean(), 17);
115+
}
116+
117+
self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - \PHP_INT_SIZE, \PHP_INT_SIZE));
118+
}
83119
}

src/Php72/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Symfony Polyfill / Php72
33

44
This component provides functions added to PHP 7.2 core:
55

6+
- [`spl_object_id`](https://php.net/spl_object_id)
67
- [`stream_isatty`](https://php.net/stream_isatty)
78

89
On Windows only:

src/Php72/bootstrap.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ function stream_isatty($stream) { return function_exists('posix_isatty') && @pos
2222
function utf8_encode($s) { return p\Php72::utf8_encode($s); }
2323
function utf8_decode($s) { return p\Php72::utf8_decode($s); }
2424
}
25+
if (!function_exists('spl_object_id')) {
26+
function spl_object_id($s) { return p\Php72::spl_object_id($s); }
27+
}
2528
if (!defined('PHP_OS_FAMILY')) {
2629
define('PHP_OS_FAMILY', p\Php72::php_os_family());
2730
}

tests/Php72/Php72Test.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,20 @@ public function testPhpOsFamily()
4848
$this->assertTrue(defined('PHP_OS_FAMILY'));
4949
$this->assertSame(PHP_OS_FAMILY, p::php_os_family());
5050
}
51+
52+
/**
53+
* @covers Symfony\Polyfill\Php72\Php72::spl_object_id
54+
*/
55+
public function testSplObjectId()
56+
{
57+
$obj = new \stdClass();
58+
$id = spl_object_id($obj);
59+
ob_start();
60+
var_dump($obj);
61+
$dump = ob_get_clean();
62+
63+
$this->assertStringStartsWith("object(stdClass)#$id ", $dump);
64+
65+
$this->assertNull(@spl_object_id(123));
66+
}
5167
}

0 commit comments

Comments
 (0)