interface I {
// We may naively assume that the PHP constant is always a string.
const PHP = 'PHP 8.2';
}
class Foo implements I {
// But implementing classes may define it as an array.
const PHP = [];
}
interface I {
const string PHP = 'PHP 8.3';
}
class Foo implements I {
const string PHP = [];
}
// Fatal error: Cannot use array as value for class constant
// Foo::PHP of type string
class Foo {
const PHP = 'PHP 8.2';
}
$searchableConstant = 'PHP';
var_dump(constant(Foo::class . "::{$searchableConstant}"));
class Foo {
const PHP = 'PHP 8.3';
}
$searchableConstant = 'PHP';
var_dump(Foo::{$searchableConstant});
#[\Override]
attribute RFC
use PHPUnit\Framework\TestCase;
final class MyTest extends TestCase {
protected $logFile;
protected function setUp(): void {
$this->logFile = fopen('/tmp/logfile', 'w');
}
protected function taerDown(): void {
fclose($this->logFile);
unlink('/tmp/logfile');
}
}
// The log file will never be removed, because the
// method name was mistyped (taerDown vs tearDown).
use PHPUnit\Framework\TestCase;
final class MyTest extends TestCase {
protected $logFile;
protected function setUp(): void {
$this->logFile = fopen('/tmp/logfile', 'w');
}
#[\Override]
protected function taerDown(): void {
fclose($this->logFile);
unlink('/tmp/logfile');
}
}
// Fatal error: MyTest::taerDown() has #[\Override] attribute,
// but no matching parent method exists
#[\Override]
attribute to a method, PHP will ensure that a method with the same name exists in a parent class or in an implemented interface. Adding the attribute makes it clear that overriding a parent method is intentional and simplifies refactoring, because the removal of an overridden parent method will be detected. class PHP {
public string $version = '8.2';
}
readonly class Foo {
public function __construct(
public PHP $php
) {}
public function __clone(): void {
$this->php = clone $this->php;
}
}
$instance = new Foo(new PHP());
$cloned = clone $instance;
// Fatal error: Cannot modify readonly property Foo::$php
class PHP {
public string $version = '8.2';
}
readonly class Foo {
public function __construct(
public PHP $php
) {}
public function __clone(): void {
$this->php = clone $this->php;
}
}
$instance = new Foo(new PHP());
$cloned = clone $instance;
$cloned->php->version = '8.3';
readonly
properties may now be modified once within the magic __clone
method to enable deep-cloning of readonly properties. json_validate()
function RFC
Doc
function json_validate(string $string): bool {
json_decode($string);
return json_last_error() === JSON_ERROR_NONE;
}
var_dump(json_validate('{ "test": { "foo": "bar" } }')); // true
var_dump(json_validate('{ "test": { "foo": "bar" } }')); // true
json_validate()
allows to check if a string is syntactically valid JSON, while being more efficient than json_decode()
. Randomizer::getBytesFromString()
method RFC
Doc
// This function needs to be manually implemented.
function getBytesFromString(string $string, int $length) {
$stringLength = strlen($string);
$result = '';
for ($i = 0; $i < $length; $i++) {
// random_int is not seedable for testing, but secure.
$result .= $string[random_int(0, $stringLength - 1)];
}
return $result;
}
$randomDomain = sprintf(
"%s.example.com",
getBytesFromString(
'abcdefghijklmnopqrstuvwxyz0123456789',
16,
),
);
echo $randomDomain;
// A \Random\Engine may be passed for seeding,
// the default is the secure engine.
$randomizer = new \Random\Randomizer();
$randomDomain = sprintf(
"%s.example.com",
$randomizer->getBytesFromString(
'abcdefghijklmnopqrstuvwxyz0123456789',
16,
),
);
echo $randomDomain;
Randomizer::getFloat()
and Randomizer::nextFloat()
methods RFC
Doc
// Returns a random float between $min and $max, both including.
function getFloat(float $min, float $max) {
// This algorithm is biased for specific inputs and may
// return values outside the given range. This is impossible
// to work around in userland.
$offset = random_int(0, PHP_INT_MAX) / PHP_INT_MAX;
return $offset * ($max - $min) + $min;
}
$temperature = getFloat(-89.2, 56.7);
$chanceForTrue = 0.1;
// getFloat(0, 1) might return the upper bound, i.e. 1,
// introducing a small bias.
$myBoolean = getFloat(0, 1) < $chanceForTrue;
$randomizer = new \Random\Randomizer();
$temperature = $randomizer->getFloat(
-89.2,
56.7,
\Random\IntervalBoundary::ClosedClosed,
);
$chanceForTrue = 0.1;
// Randomizer::nextFloat() is equivalent to
// Randomizer::getFloat(0, 1, \Random\IntervalBoundary::ClosedOpen).
// The upper bound, i.e. 1, will not be returned.
$myBoolean = $randomizer->nextFloat() < $chanceForTrue;
Due to the limited precision and implicit rounding of floating point numbers, generating an unbiased float lying within a specific interval is non-trivial and the commonly used userland solutions may generate biased results or numbers outside the requested range.
The Randomizer was also extended with two methods to generate random floats in an unbiased fashion. The Randomizer::getFloat()
method uses the γ-section algorithm that was published in Drawing Random Floating-Point Numbers from an Interval. Frédéric Goualard, ACM Trans. Model. Comput. Simul., 32:3, 2022.
php -l foo.php bar.php
No syntax errors detected in foo.php
php -l foo.php bar.php
No syntax errors detected in foo.php
No syntax errors detected in bar.php
The command line linter now accepts variadic input for filenames to lint
DOMElement::getAttributeNames()
, DOMElement::insertAdjacentElement()
, DOMElement::insertAdjacentText()
, DOMElement::toggleAttribute()
, DOMNode::contains()
, DOMNode::getRootNode()
, DOMNode::isEqualNode()
, DOMNameSpaceNode::contains()
, and DOMParentNode::replaceChildren()
methods.IntlCalendar::setDate()
, IntlCalendar::setDateTime()
, IntlGregorianCalendar::createFromDate()
, and IntlGregorianCalendar::createFromDateTime()
methods.ldap_connect_wallet()
, and ldap_exop_sync()
functions.mb_str_pad()
function.posix_sysconf()
, posix_pathconf()
, posix_fpathconf()
, and posix_eaccess()
functions.ReflectionMethod::createFromMethodName()
method.socket_atmark()
function.str_increment()
, str_decrement()
, and stream_context_set_options()
functions.ZipArchive::getArchiveFlag()
method.zend.max_allowed_stack_size
to set the maximum allowed stack size.n
to an empty array will now make sure that the next index is n + 1
instead of 0
.range()
function.U_MULTIPLE_DECIMAL_SEPERATORS
constant is deprecated in favor of U_MULTIPLE_DECIMAL_SEPARATORS
.MT_RAND_PHP
Mt19937 variant is deprecated.ReflectionClass::getStaticProperties()
is no longer nullable.assert.active
, assert.bail
, assert.callback
, assert.exception
, and assert.warning
have been deprecated.get_class()
and get_parent_class()
without arguments are deprecated.