Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ PHP NEWS
- Standard:
. Fixed bug GH-19926 (reset internal pointer earlier while splicing array
while COW violation flag is still set). (alexandre-daubois)
. Added form feed (\f) in the default trimmed characters of trim(), rtrim()
and ltrim(). (Weilin Du)
. Invalid mode values now throw in array_filter() instead of being silently
defaulted to 0. (Jorg Sowa)
. Fixed bug GH-21058 (error_log() crashes with message_type 3 and
Expand Down
2 changes: 2 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ PHP 8.6 UPGRADE NOTES
- Standard:
. Invalid mode values now throw in array_filter() instead of being silently
defaulted to 0.
. Form feed (\f) is now added in the default trimmed characters of trim(),
rtrim() and ltrim(). RFC: https://wiki.php.net/rfc/trim_form_feed

========================================
2. New Features
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/enum/no-class-implements-backed-enum.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ class Foo implements BackedEnum {}

?>
--EXPECTF--
Fatal error: Non-enum class Foo cannot implement interface BackedEnum in %s on line %d
Fatal error: Non-enum class Foo cannot implement interface UnitEnum in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Interface that is extended from Enum only interface shouldn't be implementable by non-enum class
--FILE--
<?php
interface I extends UnitEnum {}

class C implements I {
public static function cases(): array {
return [];
}
}

?>
--EXPECTF--
Fatal error: Non-enum class C cannot implement interface UnitEnum in %s on line %d
8 changes: 4 additions & 4 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1417,7 +1417,7 @@ static zend_string *resolve_class_name(zend_string *name, const zend_class_entry
}

static zend_string *add_intersection_type(zend_string *str,
const zend_type_list *intersection_type_list, zend_class_entry *scope,
const zend_type_list *intersection_type_list,
bool is_bracketed)
{
const zend_type *single_type;
Expand All @@ -1442,19 +1442,19 @@ static zend_string *add_intersection_type(zend_string *str,
return str;
}

zend_string *zend_type_to_string_resolved(const zend_type type, zend_class_entry *scope) {
zend_string *zend_type_to_string_resolved(const zend_type type, const zend_class_entry *scope) {
zend_string *str = NULL;

/* Pure intersection type */
if (ZEND_TYPE_IS_INTERSECTION(type)) {
ZEND_ASSERT(!ZEND_TYPE_IS_UNION(type));
str = add_intersection_type(str, ZEND_TYPE_LIST(type), scope, /* is_bracketed */ false);
str = add_intersection_type(str, ZEND_TYPE_LIST(type), /* is_bracketed */ false);
} else if (ZEND_TYPE_HAS_LIST(type)) {
/* A union type might not be a list */
const zend_type *list_type;
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
str = add_intersection_type(str, ZEND_TYPE_LIST(*list_type), scope, /* is_bracketed */ true);
str = add_intersection_type(str, ZEND_TYPE_LIST(*list_type), /* is_bracketed */ true);
continue;
}
ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ int ZEND_FASTCALL zendlex(zend_parser_stack_elem *elem);

void zend_assert_valid_class_name(const zend_string *const_name, const char *type);

zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope);
zend_string *zend_type_to_string_resolved(zend_type type, const zend_class_entry *scope);
ZEND_API zend_string *zend_type_to_string(zend_type type);

/* class fetches */
Expand Down
27 changes: 14 additions & 13 deletions Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ static void add_property_hook_obligation(
zend_class_entry *ce, const zend_property_info *hooked_prop, const zend_function *hook_func);

static void ZEND_COLD emit_incompatible_method_error(
const zend_function *child, zend_class_entry *child_scope,
const zend_function *parent, zend_class_entry *parent_scope,
const zend_function *child, const zend_class_entry *child_scope,
const zend_function *parent, const zend_class_entry *parent_scope,
inheritance_status status);

static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent);
Expand Down Expand Up @@ -320,7 +320,7 @@ static bool unlinked_instanceof(const zend_class_entry *ce1, const zend_class_en
}

if (ce1->parent) {
zend_class_entry *parent_ce;
const zend_class_entry *parent_ce;
if (ce1->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
parent_ce = ce1->parent;
} else {
Expand Down Expand Up @@ -671,7 +671,7 @@ static inheritance_status zend_is_intersection_subtype_of_type(
return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
}

ZEND_API inheritance_status zend_perform_covariant_type_check(
static inheritance_status zend_perform_covariant_type_check(
zend_class_entry *fe_scope, const zend_type fe_type,
zend_class_entry *proto_scope, const zend_type proto_type)
{
Expand Down Expand Up @@ -763,8 +763,8 @@ ZEND_API inheritance_status zend_perform_covariant_type_check(
}

static inheritance_status zend_do_perform_arg_type_hint_check(
zend_class_entry *fe_scope, zend_arg_info *fe_arg_info,
zend_class_entry *proto_scope, zend_arg_info *proto_arg_info) /* {{{ */
zend_class_entry *fe_scope, const zend_arg_info *fe_arg_info,
zend_class_entry *proto_scope, const zend_arg_info *proto_arg_info) /* {{{ */
{
if (!ZEND_TYPE_IS_SET(fe_arg_info->type) || ZEND_TYPE_PURE_MASK(fe_arg_info->type) == MAY_BE_ANY) {
/* Child with no type or mixed type is always compatible */
Expand Down Expand Up @@ -897,7 +897,7 @@ static inheritance_status zend_do_perform_implementation_check(
/* }}} */

static ZEND_COLD void zend_append_type_hint(
smart_str *str, zend_class_entry *scope, const zend_arg_info *arg_info, bool return_hint) /* {{{ */
smart_str *str, const zend_class_entry *scope, const zend_arg_info *arg_info, bool return_hint) /* {{{ */
{
if (ZEND_TYPE_IS_SET(arg_info->type)) {
zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope);
Expand All @@ -911,7 +911,7 @@ static ZEND_COLD void zend_append_type_hint(
/* }}} */

static ZEND_COLD zend_string *zend_get_function_declaration(
const zend_function *fptr, zend_class_entry *scope) /* {{{ */
const zend_function *fptr, const zend_class_entry *scope) /* {{{ */
{
smart_str str = {0};

Expand Down Expand Up @@ -1054,8 +1054,8 @@ static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
}

static void ZEND_COLD emit_incompatible_method_error(
const zend_function *child, zend_class_entry *child_scope,
const zend_function *parent, zend_class_entry *parent_scope,
const zend_function *child, const zend_class_entry *child_scope,
const zend_function *parent, const zend_class_entry *parent_scope,
inheritance_status status) {
zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope);
zend_string *child_prototype = zend_get_function_declaration(child, child_scope);
Expand Down Expand Up @@ -2168,6 +2168,10 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
zend_class_constant *c;
uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY;

if (iface->num_interfaces) {
zend_do_inherit_interfaces(ce, iface);
}

if (!(ce->ce_flags & ZEND_ACC_INTERFACE)) {
/* We are not setting the prototype of overridden interface methods because of abstract
* constructors. See Zend/tests/interface_constructor_prototype_001.phpt. */
Expand Down Expand Up @@ -2199,9 +2203,6 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
} ZEND_HASH_FOREACH_END();

do_implement_interface(ce, iface);
if (iface->num_interfaces) {
zend_do_inherit_interfaces(ce, iface);
}
}
/* }}} */

Expand Down
8 changes: 4 additions & 4 deletions ext/standard/basic_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -2318,16 +2318,16 @@ function strcoll(string $string1, string $string2): int {}
* @frameless-function {"arity": 1}
* @frameless-function {"arity": 2}
*/
function trim(string $string, string $characters = " \n\r\t\v\0"): string {}
function trim(string $string, string $characters = " \f\n\r\t\v\0"): string {}

/** @compile-time-eval */
function rtrim(string $string, string $characters = " \n\r\t\v\0"): string {}
function rtrim(string $string, string $characters = " \f\n\r\t\v\0"): string {}

/** @alias rtrim */
function chop(string $string, string $characters = " \n\r\t\v\0"): string {}
function chop(string $string, string $characters = " \f\n\r\t\v\0"): string {}

/** @compile-time-eval */
function ltrim(string $string, string $characters = " \n\r\t\v\0"): string {}
function ltrim(string $string, string $characters = " \f\n\r\t\v\0"): string {}

/**
* @compile-time-eval
Expand Down
4 changes: 2 additions & 2 deletions ext/standard/basic_functions_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions ext/standard/basic_functions_decl.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 9 additions & 10 deletions ext/standard/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -515,11 +515,16 @@ static inline zend_result php_charmask(const unsigned char *input, size_t len, c
}
/* }}} */

static zend_always_inline bool php_is_whitespace(unsigned char c)
{
return c <= ' ' && (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\0');
}

/* {{{ php_trim_int()
* mode 1 : trim left
* mode 2 : trim right
* mode 3 : trim left and right
* what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
* what indicates which chars are to be trimmed. NULL->default (' \f\t\n\r\v\0')
*/
static zend_always_inline zend_string *php_trim_int(zend_string *str, const char *what, size_t what_len, int mode)
{
Expand Down Expand Up @@ -573,10 +578,7 @@ static zend_always_inline zend_string *php_trim_int(zend_string *str, const char
} else {
if (mode & 1) {
while (start != end) {
unsigned char c = (unsigned char)*start;

if (c <= ' ' &&
(c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\0')) {
if (php_is_whitespace((unsigned char)*start)) {
start++;
} else {
break;
Expand All @@ -585,10 +587,7 @@ static zend_always_inline zend_string *php_trim_int(zend_string *str, const char
}
if (mode & 2) {
while (start != end) {
unsigned char c = (unsigned char)*(end-1);

if (c <= ' ' &&
(c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\0')) {
if (php_is_whitespace((unsigned char)*(end-1))) {
end--;
} else {
break;
Expand All @@ -611,7 +610,7 @@ static zend_always_inline zend_string *php_trim_int(zend_string *str, const char
* mode 1 : trim left
* mode 2 : trim right
* mode 3 : trim left and right
* what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
* what indicates which chars are to be trimmed. NULL->default (' \f\t\n\r\v\0')
*/
PHPAPI zend_string *php_trim(zend_string *str, const char *what, size_t what_len, int mode)
{
Expand Down
6 changes: 6 additions & 0 deletions ext/standard/tests/strings/trim.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ var_dump("ABC" === trim("ABC\x50\xC1\x60\x90","\x50..\xC1"));
var_dump("ABC\x50\xC1" === trim("ABC\x50\xC1\x60\x90","\x51..\xC0"));
var_dump("ABC\x50" === trim("ABC\x50\xC1\x60\x90","\x51..\xC1"));
var_dump("ABC" === trim("ABC\x50\xC1\x60\x90","\x50..\xC1"));
var_dump("ABC" === trim("\fABC\f"));
var_dump("ABC" === ltrim("\fABC"));
var_dump("ABC" === rtrim("ABC\f"));

?>
--EXPECT--
Expand All @@ -36,3 +39,6 @@ bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)