I suggest you look at the below resource:
- PHP 8.3 Changes
- Changes
- Readonly amendments
- Typed class constants
- #[Override] attribute
- Negative indices in arrays
- Anonymous readonly classes
- The new
json_validate()
function Randomizer
additions- Dynamic class constant fetch
- Traits and static properties
- Magic method closures and named arguments
- Invariant constant visibility
- Changes
overwriting readonly property values within __clone(), in order to allow deep cloning readonly properties:
<?php
readonly class Post
{
public function __construct
(
public string $title,
) {}
public function __clone()
{
$this->title = 'cloned title';
// This is allowed,
// even though `title` is a readonly property.
}
}
$post = new Post('post title');
echo $post->title . PHP_EOL;
$post_clone = clone $post;
echo $post_clone->title . PHP_EOL;
PHP Fatal error: Uncaught Error: Cannot modify readonly property Post::$title in /tmp/main.php:14
Stack trace:
#0 /tmp/main.php(24): Post->__clone()
#1 {main}
thrown in /tmp/main.php on line 14
post title
cloned title
You can now typehint class constants:
<?php
class Post
{
const string TITLE = 'this is title';
}
echo Post::TITLE . PHP_EOL;
PHP Parse error: syntax error, unexpected identifier "TITLE", expecting "=" in /tmp/main.php on line 5
this is title
The new #[Override] attribute is used to show a programmer's intent. It basically says "I know this method is overriding a parent method. If that would ever change, please let me know".
Here's an example:
class User
{
public function methodWithDefaultImplementation(): int
{
return 1;
}
}
class Admin extends User
{
#[Override]
public function methodWithNewImplementation(): int
{
return 2; // The overridden method
}
}
$admin = new Admin();
echo $admin->methodWithNewImplementation();
if I changed User/methodWithDefaultImplementation
to methodWithNewImplementation
, what will happen?
2
PHP will be able to detect that Admin::methodWithDefaultImplementation()
doesn't override anything anymore, and it will throw an error:
PHP Fatal error: Admin::methodWithDefaultImplementation() has #[\Override] attribute, but no matching parent method exists in /tmp/main.php on line 14
If you have an empty array, add an item with a negative index, and then add another item, that second item would always start at index 0:
$array = [];
$array[-5] = 'a';
$array[] = 'b';
var_export($array);
array (
-5 => 'a',
0 => 'b',
)
array (
-5 => 'a',
-4 => 'b',
)
Previously, you weren't able to mark anonymous classes as readonly. That's fixed in PHP 8.3:
$class = new readonly class {
public function __construct(
public string $title = 'this is title',
) {}
};
echo $class->title;
PHP Parse error: syntax error, unexpected token "readonly" in /tmp/main.php on line 3
this is title
Previously, the only way to validate whether a string was valid JSON, was to decode it and detect whether any errors were thrown. This new json_validate() function is beneficial if you only need to know whether the input is valid JSON, since it uses less memory compared to decoding the string.
function is_valid_json($json_string) {
$json_data = json_decode($json_string);
return (json_last_error() === JSON_ERROR_NONE) ? true : false;
}
$json_string = '{"name": "John Doe", "age": 30}';
if (is_valid_json($json_string)) {
echo "Valid JSON string";
} else {
echo "Invalid JSON string";
}
// Valid JSON string
$json_string = '{"name": "John Doe", "age": 30}';
if (json_validate($json_string)) {
echo "Valid JSON string";
} else {
echo "Invalid JSON string";
}
// Valid JSON string
PHP 8.2 added the new Randomizer class. This update brings some small additions:
<?php
use Random\Randomizer;
$random = new Randomizer();
echo $random->getBytesFromString('milad',2);
// ma
getFloat()
returns a float between $min and $max
<?php
use Random\Randomizer;
$random = new Randomizer();
echo $random->getFloat(min: 1,max: 10);
//4.2490697405757
nextFloat()
is a shorthand for getFloat(0, 1, IntervalBoundary::ClosedOpen)
, in other words: it'll give you a random float between 0 and 1, where 1 is excluded.
<?php
use Random\Randomizer;
$random = new Randomizer();
echo $random->nextFloat();
// 0.13968670649046
PHP 8.3 allows you to fetch constants with a more dynamic syntax:
<?php
class Post
{
const TITLE = 'this is title';
}
$name = 'TITLE';
echo constant(Post::class . '::' . $name);
// this is title
<?php
class Post
{
const TITLE = 'this is title';
}
$name = 'TITLE';
echo Post::{$name};
// this is title
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.
<?php
trait Commentable
{
public static string $comment = 'this is comment';
}
class Post
{
use Commentable;
public function getStaticPro()
{
self::$comment = 'post comment';
return self::$comment;
}
}
class Child extends Post
{
use Commentable;
public function getStaticPro()
{
return self::$comment;
}
}
$post = new Post();
$child = new Child();
echo $post->getStaticPro() . PHP_EOL;
echo $child->getStaticPro() . PHP_EOL;
post comment
post comment
post comment
this is comment
Let's say you have a class that supports magic methods:
class Test {
public function __call($name, $args)
{
var_dump($name, $args);
}
public static function __callStatic($name, $args) {
var_dump($name, $args);
}
}
PHP 8.3 allows you to create closures from those methods, and then pass named arguments to those closures. That wasn't possible before.
$test = new Test();
$closure = $test->magic(...);
$closure(a: 'hello', b: 'world');
PHP Fatal error: Uncaught Error: Unknown named parameter $a in /tmp/main.php:18
Stack trace:
#0 {main}
thrown in /tmp/main.php on line 18
string(5) "magic"
array(2) {
["a"]=>
string(5) "hello"
["b"]=>
string(5) "world"
}
Previously, visibility for constants weren't checked when implementing an interface. PHP 8.3 fixes this bug, but it might lead to code breaking in some places if you weren't aware of this behaviour.
<?php
interface I {
public const TITLE = 'this is title';
}
class Post implements I {
private const TITLE = 'post title';
public function getTitle()
{
return self::TITLE;
}
}
$c = new Post();
echo $c->getTitle() . PHP_EOL;
post title
PHP Fatal error: Access level to Post::TITLE must be public (as in interface I) in /tmp/main.php on line 6