#php80
June 25th ~ July 23rd - Alphas (1, 2, 3)
August 4th ~ Feature Freeze (F.F ❄️)
August 6th ~ September 17th - Betas (1, 2, 3, 4)
October 1st ~ November 12th - Release Candidates (1, 2, 3, 4, 5)
26th November - General Availability (G.A. 🔥)
#php80
PHP 7.2 - Won't be supported
PHP 7.3 - Security Fixes only
PHP 7.4 - Active Support
PHP 8.0 - Active Support
#php80
#php80
#php80
- Don't expect performance improvements like PHP 5.6 ~> PHP 7.0
- Heavy Processes will benefit from it, not simple and fast APIs
- https://youtu.be/g3RPYtwP1jk: Benoit Jacquemont (in French)
- https://youtu.be/JZAs1YTcRHM: Nickolas da Silva (in Portuguese)
- https://youtu.be/5H77TnoLLcU: Nikita Popov (in English)
- https://youtu.be/7UOWus-5yxg: Dmitry Stogov (in Russian)
- Since PHP 7.4, AWS has been helping PHP by providing performance improvements patches
- Blog post with all the changes and benchmarks
#php80
`match` Control Structure
`mixed` type
`?->` Operator
Constructor Property Promotion
`Stringable` Interface
Attributes
New `string_*` functions
Weak Maps
`static` return type
Validation for abstract trait methods
New `fdiv` function
Trailing commas in more places
DOM Living Standard APIs
New `preg_last_error_msg` function
Cryptographic Message Syntax (CMS) (RFC 5652) support
Array sorting functions are now stable
Union Types
Named Arguments
`PhpToken` class
New `get_resource_id` function
`match` Control Structure
Attributes
Union Types
Named Arguments
<?php declare(strict_types=1);
class Number
{
/** @var int|float $number */
private $number;
/** @param int|float $number */
public function setNumber($number)
{
$this->number = $number;
}
/** @return int|float */
public function getNumber()
{
return $this->number;
}
}
<?php declare(strict_types=1);
class Number
{
/** @var int|float $number */
private $number;
/** @param int|float $number */
public function setNumber($number)
{
$this->number = $number;
}
/** @return int|float */
public function getNumber()
{
return $this->number;
}
}
$number = new Number();
$number->setNumber('string');
echo $number->getNumber(); // 'string'
<?php declare(strict_types=1);
class Number
{
/** @var int|float $number */
private $number;
/** @param int|float $number */
public function setNumber($number)
{
if (!is_int($number) && !is_float($number)) {
throw new \InvalidArgumentException(
sprintf('Argument $number should be either an integer or float, %s given', gettype($number))
);
}
$this->number = $number;
}
/** @return int|float */
public function getNumber()
{
return $this->number;
}
}
$number = new Number();
$number->setNumber('string'); // InvalidArgumentException: Argument $number should be either an integer or float, string given
<?php declare(strict_types=1);
class Number
{
private int|float $number;
public function setNumber(int|float $number): void
{
$this->number = $number;
}
public function getNumber(): int|float
{
return $this->number;
}
}
<?php declare(strict_types=1);
class Number
{
private int|float $number;
public function setNumber(int|float $number): void
{
$this->number = $number;
}
public function getNumber(): int|float
{
return $this->number;
}
}
$number = new Number();
$number->setNumber('string'); // Number::setNumber(): Argument #1 ($number) must be of type int|float, string given
<?php declare(strict_types=1);
class Collection
{
private array $items;
public function setItem(string $index, array|bool|callable|int|float|null|object|string $value): void
{
$this->items[$index] = $value;
}
public function getItem(string $index): array|bool|callable|int|float|null|object|string
{
return $this->items[$index];
}
}
<?php declare(strict_types=1);
class Collection
{
private array $items;
public function setItem(string $index, mixed $value): void
{
$this->items[$index] = $value;
}
public function getItem(string $index): mixed
{
return $this->items[$index];
}
}
<?php declare(strict_types=1);
$value = '2';
switch ($value) {
case 0:
$result = 'Foo';
break;
case 1:
$result = 'Bar';
break;
case 2:
$result = 'Baz';
break;
}
echo $result; // 'Baz'
<?php declare(strict_types=1);
$value = '3';
switch ($value) {
case 0:
$result = 'Foo';
break;
case 1:
$result = 'Bar';
break;
case 2:
$result = 'Baz';
break;
}
echo $result; // Warning: Undefined variable $result
<?php declare(strict_types=1);
$value = '3';
switch ($value) {
case 0:
$result = 'Foo';
break;
case 1:
$result = 'Bar';
break;
case 2:
$result = 'Baz';
break;
default:
throw new \InvalidArgumentException(sprintf('No `case` for $value %s', $value));
}
echo $result; // InvalidArgumentException: No `case` for $value 3
<?php declare(strict_types=1);
$value = 2;
echo match ($value) {
0 => 'Foo',
1 => 'Bar',
2 => 'Baz',
}; // Baz
<?php declare(strict_types=1);
$value = 3;
echo match ($value) {
0 => 'Foo',
1 => 'Bar',
2 => 'Baz',
}; // UnhandledMatchError: Unhandled match value of type int
<?php declare(strict_types=1);
$neighborhood = $address->getNeighborhood(); // returns either NULL or a Neighborhood object
$neighborhoodName = $neighborhood ? $neighborhood->getName() : null;
if ($neighborhoodName !== null) {
// do something with $neighborhoodName
}
<?php declare(strict_types=1);
$neighborhoodName = $address->getNeighborhood()?->getName();
if ($neighborhoodName !== null) {
// do something with $neighborhoodName
}
<?php declare(strict_types=1);
$items = [
1, 2, 'foo',
];
$integers = array_filter($items, fn (mixed $item): bool => is_int($item));
var_dump($integers); // [1, 2]
<?php declare(strict_types=1);
var_dump(
array_fill(2, 3, 'PHP')
);
<?php declare(strict_types=1);
var_dump(
array_fill(2, 3, 'PHP')
); // [2 => 'PHP', 3 => 'PHP', 4 => 'PHP']
<?php declare(strict_types=1);
var_dump(
array_fill(start_index: 2, count: 3, value: 'PHP')
); // [2 => 'PHP', 3 => 'PHP', 4 => 'PHP']
<?php declare(strict_types=1);
class Person
{
public function __construct(string $name, int $age)
{
// ...
}
}
new Person(name: 'Gabriel Caruso', age: 23);
<?php declare(strict_types=1);
interface Person
{
public function setName(string $name);
}
class MyPerson implements Person
{
public function setName(string $fullName) {}
}
$person = (new MyPerson)->setName('Gabriel Caruso'); // fullName or name?
<?php declare(strict_types=1);
interface Person
{
public function setName(string $name);
}
class MyPerson implements Person
{
public function setName(string $fullName) {}
}
$person = (new MyPerson)->setName(fullName: 'Gabriel Caruso'); // Named Arguments allows renaming
<?php declare(strict_types=1);
class User
{
public function __construct(
bool $admin,
bool $active,
?array $rules = [],
) {
// Construct the object...
}
}
$user = new User(true, false, null);
<?php declare(strict_types=1);
class User
{
public function __construct(
bool $admin,
bool $active,
?array $rules = [],
) {
// Construct the object...
}
}
$user = new User(
admin: true,
active: false,
rules: null
);
<?php declare(strict_types=1);
function randomOrder(int $arg1, string $arg2, float $arg3) {}
randomOrder(arg2: 'PHP', arg3: 8.0, arg1: 1);
function optionals(string $arg1 = 'default', int $arg2 = 1) {}
optionals(arg2: 3);
function skipping(int $arg1, string $arg2, float $arg3) {}
skipping(1, 'PHP', arg3: 8.0); // This is allowed
skipping(1, arg2: 'PHP', 8.0); // Fatal error: Cannot use positional argument after named argument
<?php declare(strict_types=1);
/** @Entity */
final class User
{
/**
* @ORM\Id()
* @ORM\Column(type="integer")
*/
private int $id;
/** @ORM\Column() */
private string $name;
}
They are used to document your code, and only that.
Attributes change the behavior of your code. You can have your Entities' attributes, you can configure how properties will be (de)serialized, and even declare API routes with it
<?php declare(strict_types=1);
#[Entity]
final class User
{
#[ORM\Id()]
#[ORM\Column(type="integer")]
private int $id;
#[ORM\Column()]
private string $name;
}
- A lot of libraries, projects and framework have their own implementation. This will be centralized now
- Caching, optimization and all the good stuff that PHP offers out of the box
- Annotations will be used for annotation only
- Don't convert Annotations what were used as Attributes before checking if your library, or framework, supports it
- Take a look into the RFC, under the "Reflection" section to check how to support Attributes
<?php declare(strict_types=1);
$callable = fn() => throw new Exception(); // this was not possible before PHP 8.0
$value = $nullableValue ?? throw new InvalidArgumentException(); // `throw` is now considered an expression
#php80
<?php declare(strict_types=1);
try {
$this->login($user);
} catch (PermissionException) { // $exception variable is no longer required
throw AuthenticationException::failedLogin();
}
#php80
<?php declare(strict_types=1);
namespace Foo\Bar {
class Baz {}
$baz = new \Foo\Bar\Baz();
var_dump(
$baz::class, // "Foo\Bar\Baz"
);
}
#php80
<?php declare(strict_types=1);
namespace Foo\Bar {
class Baz {}
$baz = new \Foo\Bar\Baz();
var_dump(
$baz::class, // "Foo\Bar\Baz"
get_class($baz) // "Foo\Bar\Baz"
);
}
#php80
- Moved from `PDO::ERRMODE_SILENT` to `PDO::ERRMODE_EXCEPTION`
- This change will help new developers to understand their mistakes when dealing with PDO, avoiding common `call to fetch() on non-object` errors
- Common `SQL syntax` problems will now be exposed by PDO
#php80
<?php declare(strict_types=1);
function test(string $param = '', $param2) {
// do something with $param and $param2
}
// Deprecated: Required parameter $param2 follows optional parameter $param
#php80
- Use of case-insensitive constants / handling of true/false/null
- Declaration of case-insensitive constants
- PHP 4 constructors like
- Calling non-static methods statically
- Undocumented MBString function aliases
- Cast `(unset)`
- Check the linked PR for the full list...
#php80
<?php declare(strict_types=1);
class Foo
{
public function __toString(): bool
{
return true;
}
}
// Declaration of Foo::__toString(): bool must be compatible with Stringable::__toString(): string
#php80
<?php declare(strict_types=1);
$result = [] % [42]; // It will throw a "TypeError: Unsupported operand types"
$array = [2, 3];
$array++; // It will throw a "TypeError: Cannot increment array"
$object = new stdClass();
$object++; // It will throw a "TypeError: Cannot increment stdClass"
#php80
<?php declare(strict_types=1);
var_dump(
0 == "0", // continues to be true
0 == "0.0", // continues to be true
0 == "foo", // was true, now is false
0 == "", // was true, now is false
42 == " 42", // continues to be true
42 == "42foo", // was true, now is false
);
#php80
<?php declare(strict_types=1);
$reflectionFunction = new ReflectionFunction('array_filter');
foreach ($reflectionFunction->getParameters() as $parameter) {
echo sprintf('Parameter $%s, type %s', $parameter->getName(), $parameter->getType() ?? '*NO TYPE DEFINED*') . PHP_EOL;
}
echo 'array_filter return type: ' . $reflectionFunction->getReturnType() ?? '*NO TYPE DEFINED*';
#php80
<?php declare(strict_types=1);
$reflectionFunction = new ReflectionFunction('array_filter');
foreach ($reflectionFunction->getParameters() as $parameter) {
echo sprintf('Parameter $%s, type %s', $parameter->getName(), $parameter->getType() ?? '*NO TYPE DEFINED*') . PHP_EOL;
}
echo 'array_filter return type: ' . $reflectionFunction->getReturnType() ?? '*NO TYPE DEFINED*';
// Before PHP 8.0
// Parameter $arg, type *NO TYPE DEFINED*
// Parameter $callback, type *NO TYPE DEFINED*
// Parameter $use_keys, type *NO TYPE DEFINED*
// array_filter return type: *NO TYPE DEFINED*
#php80
<?php declare(strict_types=1);
$reflectionFunction = new ReflectionFunction('array_filter');
foreach ($reflectionFunction->getParameters() as $parameter) {
echo sprintf('Parameter $%s, type %s', $parameter->getName(), $parameter->getType() ?? '*NO TYPE DEFINED*') . PHP_EOL;
}
echo 'array_filter return type: ' . $reflectionFunction->getReturnType() ?? '*NO TYPE DEFINED*';
// After PHP 8.0
// Parameter $array, type array
// Parameter $callback, type ?callable
// Parameter $use_keys, type int
// array_filter return type: array
#php80
#php80
- Default `error_reporting` level is `E_ALL`. Previously it was excluding `E_NOTICE` and `E_DEPRECATED`
- `zend.exception_string_param_max_len` is configurable, improving `Throwable::getTraceAsString()`
- `assert.exception` default value is `true`, throwing an Exception instead of just raising a Warning
#php80
Gabriel Caruso (his first time)
Sara Golemon (PHP 7.2 manager)
#php80
- Responsible for taking care and coordinate all the Releases from Alpha 1 until G.A
- Responsible for releasing a new patch version every four weeks after G.A.
- (Not official, but) Release Managers are the one spreading the word of the new version in conferences, meetups and the WWW
Dmitry Stogov (JIT)
Nikita Popov (JetBrains)
#php80
Christoph M. Becker (Microsoft)
#php80
Matteo Beccati (PDO/Postgres)
#php80
#php80
#php80
Benjamin Eberlei (Doctrine)
#php80
Thank you ♥️
Please, leave a feedback for this presentation 👉🏻
Questions? 🤔