| <?php | |
| require_once('test_base.php'); | |
| require_once('test_util.php'); | |
| use Google\Protobuf\Internal\RepeatedField; | |
| use Google\Protobuf\Internal\GPBType; | |
| use Foo\TestMessage; | |
| use Foo\TestMessage\Sub; | |
| class ArrayTest extends TestBase | |
| { | |
| ######################################################### | |
| # Test int32 field. | |
| ######################################################### | |
| public function testInt32() | |
| { | |
| $arr = new RepeatedField(GPBType::INT32); | |
| // Test append. | |
| $arr[] = MAX_INT32; | |
| $this->assertSame(MAX_INT32, $arr[0]); | |
| $arr[] = MIN_INT32; | |
| $this->assertSame(MIN_INT32, $arr[1]); | |
| $arr[] = 1.1; | |
| $this->assertSame(1, $arr[2]); | |
| $arr[] = MAX_INT32_FLOAT; | |
| $this->assertSame(MAX_INT32, $arr[3]); | |
| $arr[] = MAX_INT32_FLOAT; | |
| $this->assertSame(MAX_INT32, $arr[4]); | |
| $arr[] = '2'; | |
| $this->assertSame(2, $arr[5]); | |
| $arr[] = '3.1'; | |
| $this->assertSame(3, $arr[6]); | |
| $arr[] = MAX_INT32_STRING; | |
| $this->assertSame(MAX_INT32, $arr[7]); | |
| $this->assertEquals(8, count($arr)); | |
| for ($i = 0; $i < count($arr); $i++) { | |
| $arr[$i] = 0; | |
| $this->assertSame(0, $arr[$i]); | |
| } | |
| // Test set. | |
| $arr[0] = MAX_INT32; | |
| $this->assertSame(MAX_INT32, $arr[0]); | |
| $arr[1] = MIN_INT32; | |
| $this->assertSame(MIN_INT32, $arr[1]); | |
| $arr[2] = 1.1; | |
| $this->assertSame(1, $arr[2]); | |
| $arr[3] = MAX_INT32_FLOAT; | |
| $this->assertSame(MAX_INT32, $arr[3]); | |
| $arr[4] = MAX_INT32_FLOAT; | |
| $this->assertSame(MAX_INT32, $arr[4]); | |
| $arr[5] = '2'; | |
| $this->assertSame(2, $arr[5]); | |
| $arr[6] = '3.1'; | |
| $this->assertSame(3, $arr[6]); | |
| $arr[7] = MAX_INT32_STRING; | |
| $this->assertSame(MAX_INT32, $arr[7]); | |
| // Test foreach. | |
| $arr = new RepeatedField(GPBType::INT32); | |
| for ($i = 0; $i < 3; $i++) { | |
| $arr[] = $i; | |
| } | |
| $i = 0; | |
| foreach ($arr as $val) { | |
| $this->assertSame($i++, $val); | |
| } | |
| $this->assertSame(3, $i); | |
| } | |
| ######################################################### | |
| # Test uint32 field. | |
| ######################################################### | |
| public function testUint32() | |
| { | |
| $arr = new RepeatedField(GPBType::UINT32); | |
| // Test append. | |
| $arr[] = MAX_UINT32; | |
| $this->assertSame(-1, $arr[0]); | |
| $arr[] = -1; | |
| $this->assertSame(-1, $arr[1]); | |
| $arr[] = MIN_UINT32; | |
| $this->assertSame(MIN_UINT32, $arr[2]); | |
| $arr[] = 1.1; | |
| $this->assertSame(1, $arr[3]); | |
| $arr[] = MAX_UINT32_FLOAT; | |
| $this->assertSame(-1, $arr[4]); | |
| $arr[] = -1.0; | |
| $this->assertSame(-1, $arr[5]); | |
| $arr[] = MIN_UINT32_FLOAT; | |
| $this->assertSame(MIN_UINT32, $arr[6]); | |
| $arr[] = '2'; | |
| $this->assertSame(2, $arr[7]); | |
| $arr[] = '3.1'; | |
| $this->assertSame(3, $arr[8]); | |
| $arr[] = MAX_UINT32_STRING; | |
| $this->assertSame(-1, $arr[9]); | |
| $arr[] = '-1.0'; | |
| $this->assertSame(-1, $arr[10]); | |
| $arr[] = MIN_UINT32_STRING; | |
| $this->assertSame(MIN_UINT32, $arr[11]); | |
| $this->assertEquals(12, count($arr)); | |
| for ($i = 0; $i < count($arr); $i++) { | |
| $arr[$i] = 0; | |
| $this->assertSame(0, $arr[$i]); | |
| } | |
| // Test set. | |
| $arr[0] = MAX_UINT32; | |
| $this->assertSame(-1, $arr[0]); | |
| $arr[1] = -1; | |
| $this->assertSame(-1, $arr[1]); | |
| $arr[2] = MIN_UINT32; | |
| $this->assertSame(MIN_UINT32, $arr[2]); | |
| $arr[3] = 1.1; | |
| $this->assertSame(1, $arr[3]); | |
| $arr[4] = MAX_UINT32_FLOAT; | |
| $this->assertSame(-1, $arr[4]); | |
| $arr[5] = -1.0; | |
| $this->assertSame(-1, $arr[5]); | |
| $arr[6] = MIN_UINT32_FLOAT; | |
| $this->assertSame(MIN_UINT32, $arr[6]); | |
| $arr[7] = '2'; | |
| $this->assertSame(2, $arr[7]); | |
| $arr[8] = '3.1'; | |
| $this->assertSame(3, $arr[8]); | |
| $arr[9] = MAX_UINT32_STRING; | |
| $this->assertSame(-1, $arr[9]); | |
| $arr[10] = '-1.0'; | |
| $this->assertSame(-1, $arr[10]); | |
| $arr[11] = MIN_UINT32_STRING; | |
| $this->assertSame(MIN_UINT32, $arr[11]); | |
| } | |
| ######################################################### | |
| # Test int64 field. | |
| ######################################################### | |
| public function testInt64() | |
| { | |
| $arr = new RepeatedField(GPBType::INT64); | |
| // Test append. | |
| $arr[] = MAX_INT64; | |
| $arr[] = MIN_INT64; | |
| $arr[] = 1.1; | |
| $arr[] = '2'; | |
| $arr[] = '3.1'; | |
| $arr[] = MAX_INT64_STRING; | |
| $arr[] = MIN_INT64_STRING; | |
| if (PHP_INT_SIZE == 4) { | |
| $this->assertSame(MAX_INT64, $arr[0]); | |
| $this->assertSame(MIN_INT64, $arr[1]); | |
| $this->assertSame('1', $arr[2]); | |
| $this->assertSame('2', $arr[3]); | |
| $this->assertSame('3', $arr[4]); | |
| $this->assertSame(MAX_INT64_STRING, $arr[5]); | |
| $this->assertSame(MIN_INT64_STRING, $arr[6]); | |
| } else { | |
| $this->assertSame(MAX_INT64, $arr[0]); | |
| $this->assertSame(MIN_INT64, $arr[1]); | |
| $this->assertSame(1, $arr[2]); | |
| $this->assertSame(2, $arr[3]); | |
| $this->assertSame(3, $arr[4]); | |
| $this->assertSame(MAX_INT64, $arr[5]); | |
| $this->assertSame(MIN_INT64, $arr[6]); | |
| } | |
| $this->assertEquals(7, count($arr)); | |
| for ($i = 0; $i < count($arr); $i++) { | |
| $arr[$i] = 0; | |
| if (PHP_INT_SIZE == 4) { | |
| $this->assertSame('0', $arr[$i]); | |
| } else { | |
| $this->assertSame(0, $arr[$i]); | |
| } | |
| } | |
| // Test set. | |
| $arr[0] = MAX_INT64; | |
| $arr[1] = MIN_INT64; | |
| $arr[2] = 1.1; | |
| $arr[3] = '2'; | |
| $arr[4] = '3.1'; | |
| $arr[5] = MAX_INT64_STRING; | |
| $arr[6] = MIN_INT64_STRING; | |
| if (PHP_INT_SIZE == 4) { | |
| $this->assertSame(MAX_INT64_STRING, $arr[0]); | |
| $this->assertSame(MIN_INT64_STRING, $arr[1]); | |
| $this->assertSame('1', $arr[2]); | |
| $this->assertSame('2', $arr[3]); | |
| $this->assertSame('3', $arr[4]); | |
| $this->assertSame(MAX_INT64_STRING, $arr[5]); | |
| $this->assertEquals(MIN_INT64_STRING, $arr[6]); | |
| } else { | |
| $this->assertSame(MAX_INT64, $arr[0]); | |
| $this->assertSame(MIN_INT64, $arr[1]); | |
| $this->assertSame(1, $arr[2]); | |
| $this->assertSame(2, $arr[3]); | |
| $this->assertSame(3, $arr[4]); | |
| $this->assertSame(MAX_INT64, $arr[5]); | |
| $this->assertEquals(MIN_INT64, $arr[6]); | |
| } | |
| } | |
| ######################################################### | |
| # Test uint64 field. | |
| ######################################################### | |
| public function testUint64() | |
| { | |
| $arr = new RepeatedField(GPBType::UINT64); | |
| // Test append. | |
| $arr[] = MAX_UINT64; | |
| $arr[] = 1.1; | |
| $arr[] = '2'; | |
| $arr[] = '3.1'; | |
| $arr[] = MAX_UINT64_STRING; | |
| if (PHP_INT_SIZE == 4) { | |
| $this->assertSame(MAX_UINT64_STRING, $arr[0]); | |
| $this->assertSame('1', $arr[1]); | |
| $this->assertSame('2', $arr[2]); | |
| $this->assertSame('3', $arr[3]); | |
| $this->assertSame(MAX_UINT64_STRING, $arr[4]); | |
| } else { | |
| $this->assertSame(MAX_UINT64, $arr[0]); | |
| $this->assertSame(1, $arr[1]); | |
| $this->assertSame(2, $arr[2]); | |
| $this->assertSame(3, $arr[3]); | |
| $this->assertSame(MAX_UINT64, $arr[4]); | |
| $this->assertSame(5, count($arr)); | |
| } | |
| $this->assertSame(5, count($arr)); | |
| for ($i = 0; $i < count($arr); $i++) { | |
| $arr[$i] = 0; | |
| if (PHP_INT_SIZE == 4) { | |
| $this->assertSame('0', $arr[$i]); | |
| } else { | |
| $this->assertSame(0, $arr[$i]); | |
| } | |
| } | |
| // Test set. | |
| $arr[0] = MAX_UINT64; | |
| $arr[1] = 1.1; | |
| $arr[2] = '2'; | |
| $arr[3] = '3.1'; | |
| $arr[4] = MAX_UINT64_STRING; | |
| if (PHP_INT_SIZE == 4) { | |
| $this->assertSame(MAX_UINT64_STRING, $arr[0]); | |
| $this->assertSame('1', $arr[1]); | |
| $this->assertSame('2', $arr[2]); | |
| $this->assertSame('3', $arr[3]); | |
| $this->assertSame(MAX_UINT64_STRING, $arr[4]); | |
| } else { | |
| $this->assertSame(MAX_UINT64, $arr[0]); | |
| $this->assertSame(1, $arr[1]); | |
| $this->assertSame(2, $arr[2]); | |
| $this->assertSame(3, $arr[3]); | |
| $this->assertSame(MAX_UINT64, $arr[4]); | |
| } | |
| } | |
| ######################################################### | |
| # Test float field. | |
| ######################################################### | |
| public function testFloat() | |
| { | |
| $arr = new RepeatedField(GPBType::FLOAT); | |
| // Test append. | |
| $arr[] = 1; | |
| $this->assertEqualsWithDelta(1.0, $arr[0], MAX_FLOAT_DIFF); | |
| $arr[] = 1.1; | |
| $this->assertEqualsWithDelta(1.1, $arr[1], MAX_FLOAT_DIFF); | |
| $arr[] = '2'; | |
| $this->assertEqualsWithDelta(2.0, $arr[2], MAX_FLOAT_DIFF); | |
| $arr[] = '3.1'; | |
| $this->assertEqualsWithDelta(3.1, $arr[3], MAX_FLOAT_DIFF); | |
| $this->assertEquals(4, count($arr)); | |
| for ($i = 0; $i < count($arr); $i++) { | |
| $arr[$i] = 0; | |
| $this->assertSame(0.0, $arr[$i]); | |
| } | |
| // Test set. | |
| $arr[0] = 1; | |
| $this->assertEqualsWithDelta(1.0, $arr[0], MAX_FLOAT_DIFF); | |
| $arr[1] = 1.1; | |
| $this->assertEqualsWithDelta(1.1, $arr[1], MAX_FLOAT_DIFF); | |
| $arr[2] = '2'; | |
| $this->assertEqualsWithDelta(2.0, $arr[2], MAX_FLOAT_DIFF); | |
| $arr[3] = '3.1'; | |
| $this->assertEqualsWithDelta(3.1, $arr[3], MAX_FLOAT_DIFF); | |
| } | |
| ######################################################### | |
| # Test double field. | |
| ######################################################### | |
| public function testDouble() | |
| { | |
| $arr = new RepeatedField(GPBType::DOUBLE); | |
| // Test append. | |
| $arr[] = 1; | |
| $this->assertEqualsWithDelta(1.0, $arr[0], MAX_FLOAT_DIFF); | |
| $arr[] = 1.1; | |
| $this->assertEqualsWithDelta(1.1, $arr[1], MAX_FLOAT_DIFF); | |
| $arr[] = '2'; | |
| $this->assertEqualsWithDelta(2.0, $arr[2], MAX_FLOAT_DIFF); | |
| $arr[] = '3.1'; | |
| $this->assertEqualsWithDelta(3.1, $arr[3], MAX_FLOAT_DIFF); | |
| $this->assertEquals(4, count($arr)); | |
| for ($i = 0; $i < count($arr); $i++) { | |
| $arr[$i] = 0; | |
| $this->assertSame(0.0, $arr[$i]); | |
| } | |
| // Test set. | |
| $arr[0] = 1; | |
| $this->assertEqualsWithDelta(1.0, $arr[0], MAX_FLOAT_DIFF); | |
| $arr[1] = 1.1; | |
| $this->assertEqualsWithDelta(1.1, $arr[1], MAX_FLOAT_DIFF); | |
| $arr[2] = '2'; | |
| $this->assertEqualsWithDelta(2.0, $arr[2], MAX_FLOAT_DIFF); | |
| $arr[3] = '3.1'; | |
| $this->assertEqualsWithDelta(3.1, $arr[3], MAX_FLOAT_DIFF); | |
| } | |
| ######################################################### | |
| # Test bool field. | |
| ######################################################### | |
| public function testBool() | |
| { | |
| $arr = new RepeatedField(GPBType::BOOL); | |
| // Test append. | |
| $arr[] = true; | |
| $this->assertSame(true, $arr[0]); | |
| $arr[] = -1; | |
| $this->assertSame(true, $arr[1]); | |
| $arr[] = 1.1; | |
| $this->assertSame(true, $arr[2]); | |
| $arr[] = ''; | |
| $this->assertSame(false, $arr[3]); | |
| $this->assertEquals(4, count($arr)); | |
| for ($i = 0; $i < count($arr); $i++) { | |
| $arr[$i] = 0; | |
| $this->assertSame(false, $arr[$i]); | |
| } | |
| // Test set. | |
| $arr[0] = true; | |
| $this->assertSame(true, $arr[0]); | |
| $arr[1] = -1; | |
| $this->assertSame(true, $arr[1]); | |
| $arr[2] = 1.1; | |
| $this->assertSame(true, $arr[2]); | |
| $arr[3] = ''; | |
| $this->assertSame(false, $arr[3]); | |
| } | |
| ######################################################### | |
| # Test string field. | |
| ######################################################### | |
| public function testString() | |
| { | |
| $arr = new RepeatedField(GPBType::STRING); | |
| // Test append. | |
| $arr[] = 'abc'; | |
| $this->assertSame('abc', $arr[0]); | |
| $arr[] = 1; | |
| $this->assertSame('1', $arr[1]); | |
| $arr[] = 1.1; | |
| $this->assertSame('1.1', $arr[2]); | |
| $arr[] = true; | |
| $this->assertSame('1', $arr[3]); | |
| $this->assertEquals(4, count($arr)); | |
| for ($i = 0; $i < count($arr); $i++) { | |
| $arr[$i] = ''; | |
| $this->assertSame('', $arr[$i]); | |
| } | |
| // Test set. | |
| $arr[0] = 'abc'; | |
| $this->assertSame('abc', $arr[0]); | |
| $arr[1] = 1; | |
| $this->assertSame('1', $arr[1]); | |
| $arr[2] = 1.1; | |
| $this->assertSame('1.1', $arr[2]); | |
| $arr[3] = true; | |
| $this->assertSame('1', $arr[3]); | |
| } | |
| ######################################################### | |
| # Test message field. | |
| ######################################################### | |
| public function testMessage() | |
| { | |
| $arr = new RepeatedField(GPBType::MESSAGE, Sub::class); | |
| // Test append. | |
| $sub_m = new Sub(); | |
| $sub_m->setA(1); | |
| $arr[] = $sub_m; | |
| $this->assertSame(1, $arr[0]->getA()); | |
| $this->assertEquals(1, count($arr)); | |
| // Test set. | |
| $sub_m = new Sub(); | |
| $sub_m->setA(2); | |
| $arr[0] = $sub_m; | |
| $this->assertSame(2, $arr[0]->getA()); | |
| // Test foreach. | |
| $arr = new RepeatedField(GPBType::MESSAGE, Sub::class); | |
| for ($i = 0; $i < 3; $i++) { | |
| $arr[] = new Sub(); | |
| $arr[$i]->setA($i); | |
| } | |
| $i = 0; | |
| foreach ($arr as $val) { | |
| $this->assertSame($i++, $val->getA()); | |
| } | |
| $this->assertSame(3, $i); | |
| } | |
| ######################################################### | |
| # Test offset type | |
| ######################################################### | |
| public function testOffset() | |
| { | |
| $arr = new RepeatedField(GPBType::INT32); | |
| $arr[] = 0; | |
| $arr[0] = 1; | |
| $this->assertSame(1, $arr[0]); | |
| $this->assertSame(1, count($arr)); | |
| $arr['0'] = 2; | |
| $this->assertSame(2, $arr['0']); | |
| $this->assertSame(2, $arr[0]); | |
| $this->assertSame(1, count($arr)); | |
| $arr[0.0] = 3; | |
| $this->assertSame(3, $arr[0.0]); | |
| $this->assertSame(1, count($arr)); | |
| } | |
| public function testOffsetNegative() | |
| { | |
| $arr = new RepeatedField(GPBType::INT32); | |
| $triggered = false; | |
| $triggeredErrno = null; | |
| $triggeredErrstr = null; | |
| set_error_handler(function($errno, $errstr) use (&$triggered, &$triggeredErrno, &$triggeredErrstr) { | |
| $triggered = true; | |
| $triggeredErrno = $errno; | |
| $triggeredErrstr = $errstr; | |
| return true; | |
| }); | |
| try { | |
| $arr[-1] = 4; | |
| } finally { | |
| restore_error_handler(); | |
| } | |
| $this->assertTrue($triggered); | |
| $this->assertEquals(E_USER_ERROR, $triggeredErrno); | |
| $this->assertTrue( | |
| strpos($triggeredErrstr, "doesn't exist") !== false || | |
| strpos($triggeredErrstr, "Cannot modify element") !== false, | |
| "Unexpected error message: " . $triggeredErrstr | |
| ); | |
| } | |
| public function testInsertRemoval() | |
| { | |
| $arr = new RepeatedField(GPBType::INT32); | |
| $arr[] = 0; | |
| $arr[] = 1; | |
| $arr[] = 2; | |
| $this->assertSame(3, count($arr)); | |
| unset($arr[2]); | |
| $this->assertSame(2, count($arr)); | |
| $this->assertSame(0, $arr[0]); | |
| $this->assertSame(1, $arr[1]); | |
| $arr[] = 3; | |
| $this->assertSame(3, count($arr)); | |
| $this->assertSame(0, $arr[0]); | |
| $this->assertSame(1, $arr[1]); | |
| $this->assertSame(3, $arr[2]); | |
| } | |
| ######################################################### | |
| # Test reference in array | |
| ######################################################### | |
| public function testArrayElementIsReferenceInSetters() | |
| { | |
| // Bool elements | |
| $values = [true]; | |
| array_walk($values, function (&$value) {}); | |
| $m = new TestMessage(); | |
| $m->setRepeatedBool($values); | |
| // Int32 elements | |
| $values = [1]; | |
| array_walk($values, function (&$value) {}); | |
| $m = new TestMessage(); | |
| $m->setRepeatedInt32($values); | |
| // Double elements | |
| $values = [1.0]; | |
| array_walk($values, function (&$value) {}); | |
| $m = new TestMessage(); | |
| $m->setRepeatedDouble($values); | |
| // String elements | |
| $values = ['a']; | |
| array_walk($values, function (&$value) {}); | |
| $m = new TestMessage(); | |
| $m->setRepeatedString($values); | |
| // Message elements | |
| $m = new TestMessage(); | |
| $subs = [1, 2]; | |
| foreach ($subs as &$sub) { | |
| $sub = new Sub(['a' => $sub]); | |
| } | |
| $m->setRepeatedMessage($subs); | |
| $this->assertTrue(true); | |
| } | |
| ######################################################### | |
| # Test memory leak | |
| ######################################################### | |
| public function testCycleLeak() | |
| { | |
| if (getenv("USE_ZEND_ALLOC") === "0") { | |
| // If we are disabling Zend's internal allocator (as we do for | |
| // Valgrind tests, for example) then memory_get_usage() will not | |
| // return a useful value. | |
| $this->markTestSkipped(); | |
| return; | |
| } | |
| gc_collect_cycles(); | |
| $arr = new RepeatedField(GPBType::MESSAGE, TestMessage::class); | |
| $arr[] = new TestMessage; | |
| $arr[0]->SetRepeatedRecursive($arr); | |
| // Clean up memory before test. | |
| gc_collect_cycles(); | |
| $start = memory_get_usage(); | |
| unset($arr); | |
| // Explicitly trigger garbage collection. | |
| gc_collect_cycles(); | |
| $end = memory_get_usage(); | |
| $this->assertLessThan($start, $end); | |
| } | |
| ######################################################### | |
| # Test incorrect types | |
| ######################################################### | |
| public function testAppendNull() | |
| { | |
| $this->expectException(TypeError::class); | |
| $arr = new RepeatedField(GPBType::MESSAGE, TestMessage::class); | |
| $arr[] = null; | |
| } | |
| ######################################################### | |
| # Test equality | |
| ######################################################### | |
| public function testEquality() | |
| { | |
| $arr = new RepeatedField(GPBType::INT32); | |
| $arr2 = new RepeatedField(GPBType::INT32); | |
| $this->assertTrue($arr == $arr2); | |
| $arr[] = 0; | |
| $arr[] = 1; | |
| $arr[] = 2; | |
| $this->assertFalse($arr == $arr2); | |
| $arr2[] = 0; | |
| $arr2[] = 1; | |
| $arr2[] = 2; | |
| $this->assertTrue($arr == $arr2); | |
| // Arrays of different types always compare false. | |
| $this->assertFalse(new RepeatedField(GPBType::INT32) == | |
| new RepeatedField(GPBType::INT64)); | |
| $this->assertFalse( | |
| new RepeatedField(GPBType::MESSAGE, TestMessage::class) == | |
| new RepeatedField(GPBType::MESSAGE, Sub::class)); | |
| } | |
| ######################################################### | |
| # Test clone | |
| ######################################################### | |
| public function testClone() | |
| { | |
| $arr = new RepeatedField(GPBType::MESSAGE, TestMessage::class); | |
| $arr[] = new TestMessage; | |
| $arr2 = clone $arr; | |
| $this->assertSame($arr[0], $arr2[0]); | |
| } | |
| ######################################################### | |
| # Test offsetUnset | |
| ######################################################### | |
| public function testOffsetUnset() | |
| { | |
| $arr = new RepeatedField(GPBType::INT32); | |
| $arr[] = 0; | |
| $arr[] = 1; | |
| $arr[] = 2; | |
| $this->assertSame(3, count($arr)); | |
| $this->assertSame(0, $arr[0]); | |
| $this->assertSame(1, $arr[1]); | |
| $this->assertSame(2, $arr[2]); | |
| $arr->offsetUnset(1); | |
| $this->assertSame(0, $arr[0]); | |
| $this->assertSame(2, $arr[1]); | |
| $arr->offsetUnset(0); | |
| $this->assertSame(2, $arr[0]); | |
| $arr->offsetUnset(0); | |
| $this->assertCount(0, $arr); | |
| } | |
| public function testIterationOutOfBoundsWithCustomErrorHandler() | |
| { | |
| $arr = new RepeatedField(GPBType::INT32); | |
| $arr[] = 1; | |
| $it = $arr->getIterator(); | |
| $it->next(); | |
| $triggered = false; | |
| $triggeredErrno = null; | |
| $triggeredErrstr = null; | |
| set_error_handler(function($errno, $errstr) use (&$triggered, &$triggeredErrno, &$triggeredErrstr) { | |
| $triggered = true; | |
| $triggeredErrno = $errno; | |
| $triggeredErrstr = $errstr; | |
| // Returning true from a custom error handler bypasses the standard PHP | |
| // error behavior (which would abort) and continues execution in the C extension. | |
| return true; | |
| }); | |
| try { | |
| $val = $it->current(); | |
| $this->assertNull($val); | |
| } finally { | |
| restore_error_handler(); | |
| } | |
| $this->assertTrue($triggered); | |
| $this->assertTrue( | |
| $triggeredErrno === E_USER_ERROR || | |
| $triggeredErrno === E_WARNING || | |
| $triggeredErrno === E_NOTICE, | |
| "Unexpected error number: " . $triggeredErrno | |
| ); | |
| if ($triggeredErrno === E_USER_ERROR) { | |
| $this->assertStringContainsString("Element at 1 doesn't exist", $triggeredErrstr); | |
| } else { | |
| // PHP implementation triggers E_WARNING/E_NOTICE with messages like: | |
| // "Undefined array key 1" (PHP 8) or "Undefined offset: 1" (PHP 7). | |
| $this->assertStringContainsString("1", $triggeredErrstr); | |
| } | |
| } | |
| } |