Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b255ef6
fix: isolate rmdir test fixtures (#23225)
NickSdot Aug 12, 2026
3046642
ext/readline: Fixed the interactive shell not waiting for the pager p…
LamentXU123 Aug 12, 2026
2c8cd7b
Merge branch 'PHP-8.5'
LamentXU123 Aug 12, 2026
257999b
Fix test file conflict on Windows (#23226)
shivammathur Aug 12, 2026
a9cd8d4
Merge branch 'PHP-8.4' into PHP-8.5
shivammathur Aug 12, 2026
8bb923e
Merge branch 'PHP-8.5'
shivammathur Aug 12, 2026
0ccff76
Fix GH-15375: nested "yield from" skips items after valid()/next()
iliaal Jul 8, 2026
a465822
Merge branch 'PHP-8.4' into PHP-8.5
iliaal Aug 12, 2026
636c1dd
Merge branch 'PHP-8.5'
iliaal Aug 12, 2026
8c90743
Fix GH-17126: get_class_methods omits __invoke for Closure (#21879)
iliaal Aug 12, 2026
a1fdc0b
ext/curl: applied fixers to improve test robustness (#23038)
NickSdot Aug 12, 2026
849d955
[skip ci] CODING_STANDARDS.md: added exception class assertion remind…
NickSdot Aug 12, 2026
f74acb6
Zend: remove zend_is_countable() (#23010)
Girgias Aug 12, 2026
e36a123
zend_language_parser: Remove unused backup_lex_pos (GH-23224)
ydah Aug 12, 2026
89a1725
Make strtolower()/strtoupper() frameless
ondrejmirtes Jul 10, 2026
f6dba91
ext/readline: Fix class constant completion in readline interactive s…
LamentXU123 Aug 12, 2026
fde23df
Revert lineno changes
iluuu1994 Aug 12, 2026
b0ae3d5
Merge branch 'PHP-8.4' into PHP-8.5
LamentXU123 Aug 12, 2026
7e130da
Merge branch 'PHP-8.5'
LamentXU123 Aug 12, 2026
70680ba
[skip ci] Fix NEWS entries in #23218
LamentXU123 Aug 12, 2026
06082ed
Merge branch 'PHP-8.4' into PHP-8.5
LamentXU123 Aug 12, 2026
88b89c0
Merge branch 'PHP-8.5'
LamentXU123 Aug 12, 2026
e213e7f
ext/snmp: Add XFAIL on several tests (#22476) (#23231)
LamentXU123 Aug 12, 2026
aca5a13
Merge branch 'PHP-8.4' into PHP-8.5
LamentXU123 Aug 12, 2026
970605b
Merge branch 'PHP-8.5'
LamentXU123 Aug 12, 2026
29f351d
[RFC] Deprecate `ReflectionProperty::setValue()` with wrong types
DanielEScherzer Aug 11, 2026
1b5de53
[RFC] Deprecate `ReflectionProperty::setRawValue()` with wrong types
DanielEScherzer Aug 11, 2026
d3f4ead
[RFC] Deprecate `ReflectionMethod` invocation for static methods with…
DanielEScherzer Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CODING_STANDARDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,21 @@ rewritten to comply with these rules.
1. Extensions should be well tested using `*.phpt` tests. Read more at
[qa.php.net](https://qa.php.net/write-test.php) documentation.

2. When testing exceptions, assert the error class in the catch block.

```diff
try {
throw new ValueError('foo');
} catch (ValueError $e) {
- echo $e->getMessage(), "\n";
+ echo $e::class, ': ', $e->getMessage(), "\n";
}

--EXPECT--
- foo
+ ValueError: foo
```

## New and experimental functions

To reduce the problems normally associated with the first public implementation
Expand Down
9 changes: 7 additions & 2 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.6.0beta2

- Core:
. Fixed bug GH-15375 (Nested "yield from" skips items after a valid() or
next() call on the inner generator). (iliaal)

- PDO_PGSQL:
. Fixed several lazy fetch (PDO::ATTR_PREFETCH => 0) defects: an infinite
loop when cleaning up a fetch left in a COPY, a use-after-free when a
statement with emulated or disabled prepares is destroyed, a connection
left busy for the next fetch, and rows delivered from a result another
statement took over. (KentarouTakeda)

- Readline:
. Fixed class constant completion in the interactive shell. (Weilin Du)

13 Aug 2026, PHP 8.6.0beta1

- Core:
Expand Down Expand Up @@ -188,8 +195,6 @@ PHP NEWS
. Implemented partial function application RFC. (Arnaud)
. Fixed bug GH-22263 (reset typed property default on every unserialize
failure path). (David Carlier)
. Fixed bug GH-18985 (Wrong line numbers for match with constant arms).
(ilutov)
. Fixed bug GH-18847 (SEGV in zend_fetch_debug_backtrace() when the memory
limit is reached while the tracing JIT enters a call frame). (Arnaud,
iliaal)
Expand Down
11 changes: 11 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,17 @@ PHP 8.6 UPGRADE NOTES
. The mysqli_get_charset() function is now deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_mysqli_get_charset

- Reflection:
. Calling ReflectionProperty::setValue() with an object that is not an
instance of the class on which the property was declared is now deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionpropertysetvalue_and_reflectionpropertysetrawvalue_with_wrong_types
. Calling ReflectionProperty::setRawValue() with an object that is not an
instance of the class on which the property was declared is now deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionpropertysetvalue_and_reflectionpropertysetrawvalue_with_wrong_types
. Calling ReflectionMethod::invoke() or ReflectionMethod::invokeArgs() with
an object and a static method is now deprecated.
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_reflectionmethodinvoke_and_reflectionmethodinvokeargs_with_objects_for_static_methods

- SPL:
. The spl_classes() function is now deprecated, use
ReflectionExtension::getClassNames() instead.
Expand Down
1 change: 1 addition & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES
. The zend_save_error_handling() function was removed.
. The zend_parse_parameter() function has been removed, use one fo the
zend_parse_arg_TYPE() APIs instead.
. The zend_is_countable() function was removed.

- Changed:
. Internal functions that return by reference are now expected to
Expand Down
89 changes: 89 additions & 0 deletions Zend/tests/generators/gh15375.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
--TEST--
GH-15375 (Nested "yield from" skips items after valid()/next() on the inner generator)
--FILE--
<?php

function arrayProvider() {
yield ['one', 'two', 'three'];
yield ['four', 'five', 'six'];
yield ['seven', 'eight', 'nine'];
}

function iterateValues(array $array) {
foreach ($array as $value) {
yield $value;
}
}

function withValid() {
foreach (arrayProvider() as $array) {
$iterator = iterateValues($array);
if ($iterator->valid()) {
yield from $iterator;
}
}
}

function withNext() {
foreach (arrayProvider() as $array) {
$iterator = iterateValues($array);
$iterator->next();
yield from $iterator;
}
}

function outer(Generator $inner) {
yield from $inner;
}

echo "valid():\n";
foreach (outer(withValid()) as $s) {
echo $s, "\n";
}

echo "next():\n";
foreach (outer(withNext()) as $s) {
echo $s, "\n";
}

// A shared, pre-primed generator consumed through two nested "yield from"
// levels must still present its current value once to each consumer (the fix
// must not over-clear the middle level's first-touch).
echo "shared primed:\n";
function counter() {
yield 1;
yield 2;
}
$gen1 = counter();
$gen1->valid();
$gen2 = outer($gen1);
$gen3 = outer($gen2);
echo "gen3 current: ", $gen3->current(), "\n";
$gen2->next();
echo "gen2 current: ", $gen2->current(), "\n";
$gen2->next();
echo "gen2 current: ", $gen2->current(), "\n";

?>
--EXPECT--
valid():
one
two
three
four
five
six
seven
eight
nine
next():
two
three
five
six
eight
nine
shared primed:
gen3 current: 1
gen2 current: 1
gen2 current: 2
48 changes: 48 additions & 0 deletions Zend/tests/get_class_methods/gh17126.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
--TEST--
GH-17126 (get_class_methods($closure) doesn't return __invoke)
--FILE--
<?php

$closure = fn (string $str) => "hello {$str}";

echo "from object:\n";
$methods = get_class_methods($closure);
sort($methods);
print_r($methods);

echo "from class name:\n";
$methods = get_class_methods('Closure');
sort($methods);
print_r($methods);

echo "unrelated class unaffected:\n";
class NoInvoke { public function foo() {} }
print_r(get_class_methods('NoInvoke'));

?>
--EXPECT--
from object:
Array
(
[0] => __invoke
[1] => bind
[2] => bindTo
[3] => call
[4] => fromCallable
[5] => getCurrent
)
from class name:
Array
(
[0] => __invoke
[1] => bind
[2] => bindTo
[3] => call
[4] => fromCallable
[5] => getCurrent
)
unrelated class unaffected:
Array
(
[0] => foo
)
17 changes: 0 additions & 17 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -5233,23 +5233,6 @@ ZEND_API bool zend_is_iterable(const zval *iterable) /* {{{ */
}
/* }}} */

ZEND_API bool zend_is_countable(const zval *countable) /* {{{ */
{
switch (Z_TYPE_P(countable)) {
case IS_ARRAY:
return 1;
case IS_OBJECT:
if (Z_OBJ_HT_P(countable)->count_elements) {
return 1;
}

return zend_class_implements_interface(Z_OBJCE_P(countable), zend_ce_countable);
default:
return 0;
}
}
/* }}} */

static zend_result get_default_via_ast(zval *default_value_zval, const char *default_value) {
zend_ast *ast;
zend_arena *ast_arena;
Expand Down
2 changes: 0 additions & 2 deletions Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -960,8 +960,6 @@ static zend_always_inline const char *zend_get_object_type_uc(const zend_class_e

ZEND_API bool zend_is_iterable(const zval *iterable);

ZEND_API bool zend_is_countable(const zval *countable);

ZEND_API void zend_convert_internal_arg_info(zend_arg_info *new_arg_info,
const zend_internal_arg_info *arg_info, bool is_return_info,
bool permanent);
Expand Down
5 changes: 5 additions & 0 deletions Zend/zend_builtin_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,11 @@ ZEND_FUNCTION(get_class_methods)
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &method_name);
}
} ZEND_HASH_FOREACH_END();

if (ce == zend_ce_closure) {
ZVAL_STR_COPY(&method_name, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE));
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &method_name);
}
}
/* }}} */

Expand Down
46 changes: 12 additions & 34 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -7165,8 +7165,6 @@ static void zend_compile_match(znode *result, zend_ast *ast)
zend_ast *arm_ast = arms->child[i];
zend_ast *body_ast = arm_ast->child[1];

CG(zend_lineno) = zend_ast_get_lineno(arm_ast);

if (arm_ast->child[0] != NULL) {
zend_ast_list *conds = zend_ast_get_list(arm_ast->child[0]);

Expand Down Expand Up @@ -10787,8 +10785,6 @@ static void zend_compile_binary_op(znode *result, zend_ast *ast) /* {{{ */
zend_compile_expr(&left_node, left_ast);
zend_compile_expr(&right_node, right_ast);

CG(zend_lineno) = ast->lineno;

if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) {
if (zend_try_ct_eval_binary_op(&result->u.constant, opcode,
&left_node.u.constant, &right_node.u.constant)
Expand Down Expand Up @@ -12290,7 +12286,7 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
return;
}

CG(zend_lineno) = zend_ast_get_lineno(ast);
CG(zend_lineno) = ast->lineno;

if ((CG(compiler_options) & ZEND_COMPILE_EXTENDED_STMT) && !zend_is_unticked_stmt(ast)) {
zend_do_extended_stmt(NULL);
Expand Down Expand Up @@ -12414,6 +12410,9 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */

static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */
{
/* CG(zend_lineno) = ast->lineno; */
CG(zend_lineno) = zend_ast_get_lineno(ast);

if (CG(memoize_mode) != ZEND_MEMOIZE_NONE) {
zend_compile_memoized_expr(result, ast, BP_VAR_R);
return;
Expand Down Expand Up @@ -12555,9 +12554,6 @@ static void zend_compile_expr(znode *result, zend_ast *ast)
{
zend_check_stack_limit();

uint32_t prev_lineno = CG(zend_lineno);
CG(zend_lineno) = zend_ast_get_lineno(ast);

uint32_t checkpoint = zend_short_circuiting_checkpoint();
zend_compile_expr_inner(result, ast);
zend_short_circuiting_commit(checkpoint, result, ast);
Expand All @@ -12567,12 +12563,12 @@ static void zend_compile_expr(znode *result, zend_ast *ast)
ZEND_ASSERT(result->op_type != IS_VAR);
}
#endif

CG(zend_lineno) = prev_lineno;
}

static zend_op *zend_compile_var_inner(znode *result, zend_ast *ast, uint32_t type, bool by_ref)
{
CG(zend_lineno) = zend_ast_get_lineno(ast);

if (CG(memoize_mode) != ZEND_MEMOIZE_NONE) {
switch (ast->kind) {
case ZEND_AST_CALL:
Expand Down Expand Up @@ -12633,9 +12629,6 @@ static zend_op *zend_compile_var(znode *result, zend_ast *ast, uint32_t type, bo
{
zend_check_stack_limit();

uint32_t prev_lineno = CG(zend_lineno);
CG(zend_lineno) = zend_ast_get_lineno(ast);

uint32_t checkpoint = zend_short_circuiting_checkpoint();
zend_op *opcode = zend_compile_var_inner(result, ast, type, by_ref);
zend_short_circuiting_commit(checkpoint, result, ast);
Expand All @@ -12649,47 +12642,32 @@ static zend_op *zend_compile_var(znode *result, zend_ast *ast, uint32_t type, bo
ZEND_ASSERT(result->op_type != IS_VAR);
}
#endif

CG(zend_lineno) = prev_lineno;

return opcode;
}

static zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type, bool by_ref) /* {{{ */
{
zend_check_stack_limit();

uint32_t prev_lineno = CG(zend_lineno);
CG(zend_lineno) = zend_ast_get_lineno(ast);

zend_op *opline;
switch (ast->kind) {
case ZEND_AST_VAR:
opline = zend_compile_simple_var(result, ast, type, true);
break;
return zend_compile_simple_var(result, ast, type, true);
case ZEND_AST_DIM:
opline = zend_delayed_compile_dim(result, ast, type, by_ref);
break;
return zend_delayed_compile_dim(result, ast, type, by_ref);
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
{
opline = zend_delayed_compile_prop(result, ast, type);
zend_op *opline = zend_delayed_compile_prop(result, ast, type);
if (by_ref) {
opline->extended_value |= ZEND_FETCH_REF;
}
break;
return opline;
}
case ZEND_AST_STATIC_PROP:
opline = zend_compile_static_prop(result, ast, type, by_ref, true);
break;
return zend_compile_static_prop(result, ast, type, by_ref, true);
default:
opline = zend_compile_var(result, ast, type, false);
break;
return zend_compile_var(result, ast, type, false);
}

CG(zend_lineno) = prev_lineno;

return opline;
}
/* }}} */

Expand Down
Loading