1 of 115

What’s New in

By Joshua Ray Copeland

2 of 115

TALK Outline

01

02

03

04

05

06

Release Schedule

Features

Breaking Changes

PHP 8.1 FEATURES

RESOURCES

SHOUTOUTS

Things to lookout for in PHP 8.1

Current & Upcoming 8.x Releases

Tons of updates and added features

Not too bad if you’ve kept up with releases

Resources for PHP 8 and this talk

The People Behind PHP 8

3 of 115

Joshua Ray Copeland

  • Programming for 12+ years
  • 10+ Years of PHP Experience
  • CTO of Remote Dev Force
  • User Group Leader of PHP Vegas
  • Husband and Father of 2 kids
  • Skateboarding, Yeezys, Vintage

4 of 115

Remote Dev Force

Hire elite software developers for your projects

Looking for Part-time Freelance Laravel/Symfony Developers

Josh@RemoteDevForce.com

5 of 115

Release Schedule

01

“My hour for tea is half-past five, and my buttered toast waits for nobody.”

6 of 115

PHP 8 Lifecycle

2020

2022

2023

Release

End-of-life

Security patches

7 of 115

https://www.php.net/supported-versions.php

8 of 115

UPGRADE OFTEN

Major.Minor.Patch7.4.9

9 of 115

Check your logs for deprecations

error_reporting=-1

10 of 115

PHP Beta Downloads

https://www.php.net/downloads

11 of 115

PHP GitHub

12 of 115

FEATURES

02

“That's the thing about people who think they hate computers. What they really hate is lousy programmers.”

13 of 115

PHP 8 Big Upgrades

  • The JIT Compiler
  • Attributes
  • Named Arguments
  • Match Expression
  • Throw expression
  • static Return Type
  • Union Types
  • mixed type

https://www.php.net/releases/8.0/en.php

14 of 115

PHP 8 Other Updates

  • Constructor Property Promotion
  • Inheritance with Private Methods
  • WeakMap implementation
  • ::class on objects
  • Nullsafe Operator
  • Non-capturing Catches for Exceptions
  • Trailing comma in parameter lists
  • Create DateTime Object from Interface
  • Stringable Interface
  • str_contains() Function

15 of 115

PHP 8 Other Updates

  • str_starts_with() Function
  • str_ends_with() Function
  • fdiv() Function
  • get_debug_type() Function
  • get_resource_id() Function
  • Abstract Method in Traits Fix
  • Objects with token_get_all()
  • Variable syntax tweaks
  • Type annotations for internal functions
  • ext-json built-in

16 of 115

The JIT Compiler

  • "JIT" stands for "just in time"
  • Great for code ran over and over again
  • More performance outside of being a web language
  • The JIT can be improved upon over time
  • Learn more from Mozilla's course on JIT compilers

17 of 115

The JIT Compiler

Downsides �

  • The “JIT” Compiler is very complex and adds a lot of code
    • When bugs pop, updates may take some time
    • Bus Factor - Dmitry/Zeev
  • Doesn’t really help web applications
    • You’re not going to see the performance boosts like you experienced with 7.0 unless you have repetitive tasks

18 of 115

Attributes

Attributes, commonly known as annotations in other languages, offers a way to add metadata to classes, without having to parse docblocks.

use App\Attributes\ExampleAttribute;

@@ExampleAttribute

class Foo

{

@@ExampleAttribute

public const FOO = 'foo';

@@ExampleAttribute

public $x;

@@ExampleAttribute

public function foo(@@ExampleAttribute $bar) { }

}

@@Attribute

class ExampleAttribute

{

public $value;

public function __construct($value)

{

$this->value = $value;

}

}

19 of 115

Attribute Drama

@@

20 of 115

RE-VOTE on ATTRIBUTE SYNTAX

21 of 115

FINAL Attribute SYNTAX

#[

ORM\Entity,

ORM\Table("user")

]

class User

{

#[ORM\Id, ORM\Column("integer"), ORM\GeneratedValue]

private $id;

#[ORM\Column("string", ORM\Column::UNIQUE)]

#[Assert\Email(["message" => "The email '{{ value }}' is not a valid email."])]

private $email;

}

22 of 115

DECLARING ATTRIBUTES

CONFIGURATIONS

Flags

#[Attribute(Attribute::TARGET_CLASS)]

class ClassAttribute

{

}

Attribute::TARGET_CLASS

Attribute::TARGET_FUNCTION

Attribute::TARGET_METHOD

Attribute::TARGET_PROPERTY

Attribute::TARGET_CLASS_CONSTANT

Attribute::TARGET_PARAMETER

Attribute::TARGET_ALL

Attribute::IS_REPEATABLE

#[Attribute(� Attribute::TARGET_METHOD |

Attribute::TARGET_FUNCTION

)]

class ClassAttribute { }

Creating Attribute Classes

23 of 115

ATTRIBUTES PARAMETER TYPES ALLOWED

zend_bool zend_is_allowed_in_const_expr(zend_ast_kind kind) /* {{{ */

{

return kind == ZEND_AST_ZVAL || kind == ZEND_AST_BINARY_OP

|| kind == ZEND_AST_GREATER || kind == ZEND_AST_GREATER_EQUAL

|| kind == ZEND_AST_AND || kind == ZEND_AST_OR

|| kind == ZEND_AST_UNARY_OP

|| kind == ZEND_AST_UNARY_PLUS || kind == ZEND_AST_UNARY_MINUS

|| kind == ZEND_AST_CONDITIONAL || kind == ZEND_AST_DIM

|| kind == ZEND_AST_ARRAY || kind == ZEND_AST_ARRAY_ELEM

|| kind == ZEND_AST_UNPACK

|| kind == ZEND_AST_CONST || kind == ZEND_AST_CLASS_CONST

|| kind == ZEND_AST_CLASS_NAME

|| kind == ZEND_AST_MAGIC_CONST || kind == ZEND_AST_COALESCE;

}

/* }}} */

24 of 115

Built-in Attributes

  • Opens up the ability to add core Attributes such as
    • #[JIT]
    • #[Deprecated]
    • And much more!

25 of 115

Attributes Event Listeners Example

class CartsProjector implements Projector

{

use ProjectsEvents;

protected array $handlesEvents = [

CartStartedEvent::class => 'onCartStarted',

CartItemAddedEvent::class => 'onCartItemAdded',

CartItemRemovedEvent::class => 'onCartItemRemoved',

];

public function onCartStarted(CartStartedEvent $event): void

{ /* … */ }

public function onCartItemAdded(CartItemAddedEvent $event): void

{ /* … */ }

public function onCartItemRemoved(CartItemRemovedEvent $event): void

{ /* … */ }

}

Before

26 of 115

Attributes Event Listeners Example

class CartsProjector implements Projector

{

use ProjectsEvents;

#[SubscribesTo(CartStartedEvent::class)]

public function onCartStarted(CartStartedEvent $event): void

{ /* … */ }

#[SubscribesTo(CartItemAddedEvent::class)]

public function onCartItemAdded(CartItemAddedEvent $event): void

{ /* … */ }

#[SubscribesTo(CartItemRemovedEvent::class)]

public function onCartItemRemoved(CartItemRemovedEvent $event): void

{ /* … */ }

}

After

27 of 115

Named Arguments

Can specify the value name and no consideration to the order.

function foo(string $a, string $b, ?string $c = null, ?string $d = null)

{ /* … */ }

foo(

b: 'value b',

a: 'value a',

d: 'value d',

);

// NEW

setcookie(

name: 'test',

expires: time() + 60 * 60 * 2,

);

// OLD

setcookie(

'test',

'',

time() + 60 * 60 * 2,

);

setcookie (

string $name,

string $value = "",

int $expires = 0,

string $path = "",

string $domain = "",

bool $secure = false,

bool $httponly = false,

) : bool

28 of 115

Named Arguments

class CustomerData

{

public function __construct(

public string $name,

public string $email,

public int $age,

) {}

}

$data = new CustomerData(

name: $input['name'],

email: $input['email'],

age: $input['age'],

);

$input = [

'age' => 25,

'name' => 'Brent',

'email' => 'brent@stitcher.io',

];

$data = new CustomerData(...$input);

$input = [

'age' => 25,

'name' => 'Brent',

'email' => 'brent@stitcher.io',

'unknownProperty' => 'This is not allowed',

];

$data = new CustomerData(...$input);

Valid

Throws an Error

$input = [

'Brent',

'age' => 25,

'email' => 'brent@stitcher.io',

];

$data = new CustomerData(...$input);

29 of 115

Named Arguments Cont.

class CustomerData

{

public static function new(...$args): self

{

return new self(...$args);

}

public function __construct(

public string $name,

public string $email,

public int $age,

) {}

}

$data = CustomerData::new(

email: 'brent@stitcher.io',

age: 25,

name: 'Brent',

);

[

'age' => 25,

'email' => 'brent@stitcher.io',

'name' => 'Brent',

]

Variadic functions

30 of 115

Named Arguments Cont.

$field = 'age';

$data = CustomerData::new(

$field: 25,

);

Not Valid

31 of 115

Named Arguments Cont.

interface EventListener {

public function on($event, $handler);

}

class MyListener implements EventListener

{

public function on($myEvent, $myHandler)

{

// …

}

}

Name is flexible for inheritance

public function register(EventListener $listener)

{

$listener->on(

event: $this->event,

handler: $this->handler,

);

}

32 of 115

Match Expression

A Cleaner Switch Expression

$result = match($input) {

0 => "hello",

'1', '2', '3' => "world",

Default => "mars"

};

33 of 115

Throw Expression

php 7.4

public function (array $input): void

{

if (! isset($input['bar'])) {

throw new BarIsMissing();

}

$bar = $input['bar'];

}

public function (array $input): void

{

$bar = $input['bar'] ?? throw new BarIsMissing();

}

php 8+

34 of 115

Static return type

php 7.4

/**

* @return static

*/

public static function newInstance()

{

return new static();

}

public static function newInstance(): static

{

return new static();

}

php 8+

35 of 115

Union Type

php 7.4

/**

* @param string|int $input

*

* @return string

*/

public function validate($input): string;

php 8+

public function validate(string|int $input): string;

36 of 115

Mixed Type

/**

* @param mixed $input

*

* @return bool

*/

public function isValid($input): bool;

  • array
  • bool
  • callable
  • int
  • float
  • null
  • object
  • resource
  • string

/**

* @param mixed $input

*

* @return bool

*/

public function isValid(mixed $input): bool;

public function isValid(mixed $input): bool;

37 of 115

Constructor Property Promotion

class Point {

public float $x;

public float $y;

public float $z;

public function __construct(

float $x = 0.0,

float $y = 0.0,

float $z = 0.0,

) {

$this->x = $x;

$this->y = $y;

$this->z = $z;

}

}

class Point {

public function __construct(

public float $x = 0.0,

public float $y = 0.0,

public float $z = 0.0,

) {}

}

38 of 115

Inheritance with Private Methods

Warning: Private methods cannot be final as they are never overridden by other classes in ...

39 of 115

Weakmap Implementation

class Foo

{

private WeakMap $cache;

public function getSomethingWithCaching(object $obj): object

{

return $this->cache[$obj]

??= $this->computeSomethingExpensive($obj);

}

}

40 of 115

::class on objects

$foo = new Foo();

var_dump($foo::class);

41 of 115

NUllsafe Operator

$startDate = $booking->getStartDate();

$dateAsString = $startDate ? $startDate->asDateTimeString() : null;

Before

After

$dateAsString = $booking->getStartDate()?->asDateTimeString();

42 of 115

Non-capturing Catches

try {

// Something goes wrong

} catch (Throwable $exception) {

Log::error("Something went wrong");

}

php < 8

php > 8

try {

// Something goes wrong

} catch (Throwable) {

Log::error("Something went wrong");

}

43 of 115

Trailing comma in parameter list

$longArgs_longVars = function (

$longArgument,

$longerArgument,

$muchLongerArgument, // Trailing commas were allowed in parameter lists in PHP 8.0

) use (

$longVar1,

$longerVar2,

$muchLongerVar3

) {

// body

};

$longArgs_longVars(

$longArgumentValue,

$obj->longMethodCall(),

$obj->longPropertyName ?? $longDefault,

);

44 of 115

Create Datetime from INTERFACE

DateTime::createFromInterface()

DatetimeImmutable::createFromInterface()

45 of 115

Stringable Interface

class Foo

{

public function __toString(): string

{

return 'foo';

}

}

function bar(string|Stringable $stringable) { /* … */ }

bar(new Foo());

bar('abc');

46 of 115

str_contains() function

OLD

NEW

if (strpos('string with lots of words', 'words') !== false) { /* … */ }

if (str_contains('string with lots of words', 'words')) { /* … */ }

47 of 115

str_starts/ends_with() functions

str_starts_with('haystack', 'hay'); // true

str_ends_with('haystack', 'stack'); // true

48 of 115

fdiv() function

fdiv(100, 0); // NAN/INF/-INF

49 of 115

get_debug_type() function

$bar = $arr['key'];

if (!($bar instanceof Foo)) {

// this shows the most simple of patterns, to get the real type an assoc array

// must be present to convert long-form "integer" into int etc.

throw new TypeError('Expected ' . Foo::class . ' got ' . (is_object($bar) ? get_class($bar) : gettype($bar)));

}

// would become

if (!($bar instanceof Foo)) {

throw new TypeError('Expected ' . Foo::class . ' got ' . get_debug_type($bar));

}

$bar->someFooMethod();

50 of 115

get_resource_id() function

$resourceId = (int) $mysqlConnection;

$resourceId = get_resource_id($mysqlConnection);

$resourceId = (int) $fileHandle;

$resourceId = get_resource_id($fileHandle);

51 of 115

PhpToken objects with get_token_all()

class PhpToken {

/** One of the T_* constants, or an integer < 256 representing a single-char token. */

public int $id;

/** The textual content of the token. */

public string $text;

/** The starting line number (1-based) of the token. */

public int $line;

/** The starting position (0-based) in the tokenized string. */

public int $pos;

/**

* Same as token_get_all(), but returning array of PhpToken.

* @return static[]

*/

public static function getAll(string $code, int $flags = 0): array;

final public function __construct(int $id, string $text, int $line = -1, int $pos = -1);

/** Get the name of the token. */

public function getTokenName(): ?string;

/**

* Whether the token has the given ID, the given text,

* or has an ID/text part of the given array.

*

* @param int|string|array $kind

*/

public function is($kind): bool;

/** Whether this token would be ignored by the PHP parser. */

public function isIgnorable(): bool;

}

52 of 115

Variable syntax tweaks

The Uniform Variable Syntax RFC resolved a number of inconsistencies in PHP's variable syntax. This RFC intends to address a small handful of cases that were overlooked.

53 of 115

Type annotation for internal functions

54 of 115

Ext-json always compiled in

55 of 115

PHP 8.1 Big Upgrades

  • Enums
  • Performance Updates
  • Array unpacking
  • Explicit octal ints
  • array_is_list func

56 of 115

ENUMS

enum Status {

case Pending;

case Active;

case Archived;

}

class User

{

public function __construct(

private Status $status = Status::Pending;

) {}

public function setStatus(Status $status): void

{ // … }

}

$user->setStatus(Status::Active);

57 of 115

Performance Improvements

Dmitry Stogov has added some improvements to opcache��"inheritance cache"��Reports between a 5% and 8% performance increase

58 of 115

Array Unpacking w/ String Keys

$array1 = ["a" => 1];

$array2 = ["b" => 2];

$array = ["a" => 0, ...$array1, ...$array2];

var_dump($array); // ["a" => 1, "b" => 2]

Already had array unpacking with Int keys��Now can use String keys w/ array unpacking

59 of 115

New “array_is_list” Function

$list = ["a", "b", "c"];

array_is_list($list); // true

$notAList = [1 => "a", 2 => "b", 3 => "c"];

array_is_list($notAList); // false

$alsoNotAList = ["a" => "a", "b" => "b", "c" => "c"];

array_is_list($alsoNotAList); // false

Determine if array is in numeric order starting at index 0

60 of 115

Explicit octal integer literal notation

016 === 0o16; // true

016 === 0O16; // true

Can now use 0o and 0O to denote octal numbers.

61 of 115

Breaking CHanges

03

“If you want to make an omelet, you gotta break some eggs”

62 of 115

Abstract methods in traits type fix

trait Test {

abstract public function test(int $input): int;

}

class UsesTrait

{

use Test;

public function test($input)

{

return $input;

}

}

php < 8 was valid

php > 8

class UsesTrait

{

use Test;

public function test(int $input): int

{

return $input;

}

}

63 of 115

Php 4 style constructor

class AnExampleObject

{

public function AnExampleObject() { }

}

class AnExampleObject

{

public function __construct() { }

}

OLD

NEW

64 of 115

Calling non-static methods with static call

class AnExampleObject

{

public function someMethod() { }

}

AnExampleObject::someMethod();

Don’t do this

65 of 115

UNSET CASTING IS GONE

$value = “value”;

(unset) $value;

OLD

NEW

$value = “value”;

unset($value);

66 of 115

Error Tracking

  • track_errors ini config has been removed
    • Meaning $php_errormsg is no longer available
  • Use error_get_last() instead if you really need to get errors...

67 of 115

CASE-INSENSITIVE CONSTANTS

  • Constants can no longer have case-insensitive names
  • 3rd arg can no longer be TRUE

68 of 115

UNDEFINED CONSTANTS

  • php < 7.2
    • A Notice and a string value with the name of the constant
  • php >= 7.2
    • A deprecation warning but still creates a string value
  • php >= 8.0
    • A Fatal error, Error Exception “Undefined constant”

69 of 115

Autoload function

public function __autoload($class) { }

OLD

NEW

spl_autoload_register() {

function($class) { }

}

70 of 115

Create function

$func = create_function(

‘$x’, ‘$y’, ‘return $x * $y’;

)

OLD

NEW

$func = function($x, $y) {

Return $x * $y;

};

71 of 115

Each function

$array = [1, 2, 3, 4];

reset($array);

while(list($key, $value) = each($array)) {

// ...

}

OLD

NEW

$array = [1, 2, 3, 4];

foreach($array as $key => $value) {

// ...

}

72 of 115

ARRAY INDEXES with NEGATIVE INTEGERS

array(3) = {

[-5] => string(3) ‘foo‘

[0] => string(3) ‘bar‘

[1] => string(3) ‘buzz‘

}

php < 8

php => 8

array(3) = {

[-5] => string(3) ‘foo‘

[-4] => string(3) ‘bar‘

[-3] => string(3) ‘buzz‘

}

$array = [ -5 => ‘foo‘ ];

$array[] = ‘bar‘;

$array[] = ‘buzz‘;

var_dump($array);

73 of 115

e_ALL and display_startup_errors

  • error_reporting
    • Default is now E_ALL
      • Includes more things than before

  • display_startup_errors
    • White screen of death now will tell you what is broken

74 of 115

Php 8.1 Breaking Changes

  • Restrict $GLOBALS usage
    • Helps performance of PHP
    • No more writes to $GLOBALS
      • Will generate a runtime error if so

// Run-time error

$GLOBALS = [];

$GLOBALS += [];

$GLOBALS =& $x;

$x =& $GLOBALS;

unset($GLOBALS);

by_ref($GLOBALS);

75 of 115

Php 8.1 Breaking Changes

  • Resource to object migrations
    • Fileinfo functions with finfo objects
    • IMAP functions with IMAPConnection objects

These no longer work with *resources, you have to use the Object versions of these when calling the related functions.

76 of 115

Php 8.1 Breaking Changes

  • Deprecate passing null to non-nullable arguments of internal functions
    • This is currently possible: str_contains("string", null);

PHP 8.1 these will generate deprecation warnings and then TypeErrors for PHP 9

77 of 115

Php 8.1 Breaking Changes

Autovivification on false

autovivification (auto-creation of arrays from falsey values).

$array = false;

$array[] = 2;

Automatic conversion of false to array is deprecated

78 of 115

MINOR Php 8.1 Breaking Changes

  • MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH no longer has an effect
  • MYSQLI_STORE_RESULT_COPY_DATA no longer has an effect
  • PDO::ATTR_STRINGIFY_FETCHES now also works with booleans
  • Integers and floats in PDO MySQL and Sqlite result sets will be returned using native PHP types instead of strings when using emulated prepared statements

79 of 115

MINOR Php 8.1 Breaking Changes

  • Functions like htmlspecialchars and htmlentities now also escape ' by default to &#039;; malformed UTF-8 will also by replaced with a unicode character, instead of resulting in an empty string
  • The hash, hash_file and hash_init have an extra argument added to them called $options, it has a default value of [] so it won't affect your code
  • New support for MurmurHash3 and xxHash

80 of 115

deprecationS

81 of 115

Default param 8.0 deprecation

<?php

function test($a = [], $b) {} // Before

function test($a, $b) {} // After

?>

<?php

function test(A $a = null, $b) {} // Still allowed

function test(?A $a, $b) {} // Recommended

?>

82 of 115

Misc 8.0 Deprecations

  • Calling get_defined_functions() with exclude_disabled explicitly set to false is deprecated and no longer has an effect. get_defined_functions() will never include disabled functions.
  • enchant_broker_set_dict_path() and enchant_broker_get_dict_path() are deprecated, because that functionality is neither available in libenchant < 1.5 nor in libenchant-2.
  • enchant_dict_add_to_personal() is deprecated; use enchant_dict_add() instead.
  • enchant_dict_is_in_session() is deprecated; use enchant_dict_is_added() instead.
  • enchant_broker_free() and enchant_broker_free_dict() are deprecated; unset the object instead.
  • The ENCHANT_MYSPELL and ENCHANT_ISPELL constants are deprecated.

83 of 115

Misc 8.0 Deprecations Cont.

  • libxml_disable_entity_loader() has been deprecated. As libxml 2.9.0 is now required, external entity loading is guaranteed to be disabled by default, and this function is no longer needed to protect against XXE attacks.
  • The constant PGSQL_LIBPQ_VERSION_STR now has the same value as PGSQL_LIBPQ_VERSION, and thus is deprecated.
  • Function aliases in the pgsql extension have been deprecated. See the following list for which functions should be used instead:

84 of 115

Misc 8.0 Deprecations Cont.

Sort comparison functions that return true or false will now throw a deprecation warning, and should be replaced with an implementation that returns an integer less than, equal to, or greater than zero.

<?php

// Replace

usort($array, fn($a, $b) => $a > $b);

// With

usort($array, fn($a, $b) => $a <=> $b);

?>

85 of 115

Misc 8.0 Deprecations Cont.

Using an empty file as ZipArchive is deprecated. Libzip 1.6.0 does not accept empty files as valid zip archives any longer. The existing workaround will be removed in the next version.

The procedural API of Zip is deprecated. Use ZipArchive instead. Iteration over all entries can be accomplished using ZipArchive::statIndex() and a for loop:

<?php

// iterate using the procedural API

assert(is_resource($zip));

while ($entry = zip_read($zip)) {

echo zip_entry_name($entry);

}

// iterate using the object-oriented API

assert($zip instanceof ZipArchive);

for ($i = 0; $entry = $zip->statIndex($i); $i++) {

echo $entry['name'];

}

?>

86 of 115

Misc 8.0 Deprecations Cont.

ReflectionFunction::isDisabled() is deprecated, as it is no longer possible to create a ReflectionFunction for a disabled function. This method now always returns false.

ReflectionParameter::getClass(), ReflectionParameter::isArray(), and ReflectionParameter::isCallable() are deprecated. ReflectionParameter::getType() and the ReflectionType APIs should be used instead.

87 of 115

Targeting 8.1 for listing as deprecated

(Under Discussion)

  • date_sunrise() and date_sunset()
  • key(), current(), next(), prev(), and reset() on objects
  • mb_check_encoding() without argument
  • get_class(), get_parent_class() and get_called_class() without argument
  • FILE_BINARY and FILE_TEXT constants
  • t fopen mode
  • Passing bool for $amountOrUpOrDown argument of IntlCalendar::roll()
  • Accessing static members on traits
  • strftime() and gmtstrftime()
  • Passing a method name as the first parameter to ReflectionMethod's constructor
  • mhash*() function family

88 of 115

PHP 8.1 Features

04

“Out with the old, in with the new”

89 of 115

PHP 8.1 Release date

NOVEMBER 25, 2021

90 of 115

Php 8.1 - enums

enum Status {

case Pending;

case Active;

case Archived;

}

91 of 115

Php 8.1 - ENUMS

class Post

{

public function __construct(

private Status $status = Status::Pending;

) {}

public function setStatus(Status $status): void

{

// …

}

}

$post->setStatus(Status::Active);

92 of 115

Php 8.1 - Fibers

$fiber = new Fiber(function (): void {

$valueAfterResuming = Fiber::suspend('after suspending');

// …

});

$valueAfterSuspending = $fiber->start();

$fiber->resume('after resuming');

93 of 115

Php 8.1 - Performance boost

“Inheritance cache”

5% - 8% performance increase thanks for dmitry

94 of 115

Php 8.1 - Array unpacking

$array1 = ["a" => 1];

$array2 = ["b" => 2];

$array = ["a" => 0, ...$array1, ...$array2];

var_dump($array); // ["a" => 1, "b" => 2]

95 of 115

Php 8.1 - Array unpacking

class MyController {

public function __construct(

private Logger $logger = new NullLogger(),

) {}

}

96 of 115

Php 8.1 - READONLY PROPERTIES

class PostData {

public function __construct(

public readonly string $title,

public readonly DateTimeImmutable $date,

) {}

}

97 of 115

Php 8.1 - READONLY PROPERTIES

class PostData {

public function __construct(

public readonly string $title,

public readonly DateTimeImmutable $date,

) {}

}

$post = new Post('Title', /* … */);

$post->title = 'Other';

Error: Cannot modify readonly property Post::$title

98 of 115

Php 8.1 - first-class callable syntax

function foo(int $a, int $b) { /* … */ }

$foo = foo(...);

$foo(a: 1, b: 2);

99 of 115

Php 8.1 - Pure Intersection Types

function generateSlug(HasTitle&HasId $post) {

return strtolower($post->getTitle()) . $post->getId();

}

100 of 115

Php 8.1 - Never Type

function dd(mixed $input): never

{

// dump

exit;

}

101 of 115

Php 8.1 - ARRAY_IS_LIST Function

$list = ["a", "b", "c"];

array_is_list($list); // true

$notAList = [1 => "a", 2 => "b", 3 => "c"];

array_is_list($notAList); // false

$alsoNotAList = ["a" => "a", "b" => "b", "c" => "c"];

array_is_list($alsoNotAList); // false

102 of 115

Php 8.1 - final class constants

class Foo

{

public const X = "foo";

}

class Bar extends Foo

{

public const X = "bar";

}

103 of 115

Php 8.1 - final class constants

class Foo

{

final public const X = "foo";

}

class Bar extends Foo

{

public const X = "bar";

Fatal error: Bar::X cannot override final constant Foo::X

}

104 of 115

Php 8.1 - fsync function

$file = fopen("sample.txt", "w");

fwrite($file, "Some content");

if (fsync($file)) {

echo "File has been successfully persisted to disk.";

}

fclose($file);

105 of 115

Php 8.1 - explicit octal integer literal notation

016 === 0o16; // true

016 === 0O16; // true

106 of 115

RESOURCES

05

“Time is the single most important resource that we have. Every single minute we lose is never coming back”

107 of 115

Migration Guide

https://www.php.net/manual/en/migration80.php

108 of 115

Helpful Packages

Type Safety

  • vimeo/psalm
  • roave/you-are-using-it-wrong
  • roave/dont

Research some shim code if you want to start using new functions

109 of 115

Video & Articles & DOCS

I built this talk with the following resources:

Sebastian Bergmann Talk on How to get ready for PHP 8Thank him for PHPUnit!

Brent’s articles on stitcher.io�Give a follow on Twitter!

PHP.net & the RFC Wiki

Great way to see what is coming down the pipeline.

reddit.com/r/PHP/

110 of 115

shoutouts

06

“Time is the single most important resource that we have. Every single minute we lose is never coming back”

111 of 115

PHP 8 is brought to you by...

Derick rethans

Sara Golemon

Dmitry & ZeEV

Gabriel Caruso

Nikita Popov

Internals

Contributor�Podcasting

PHP 8 Release Manager

JIT Compiler

PHP 8 Release Manager

OS Contributor�Submitted RFCs

112 of 115

PHP 8 Elephpant

https://inphpinity.elephpant.com

113 of 115

And thanks to all the others I forgot to mention

114 of 115

Thank You

POP QUIZ!

WHO WAS RELEASE MANAGER OF PHP 8.1?�

1 month free of

https://symfonycasts.com/

CREDITS: This presentation template was created by Slidesgo, including icons by Flaticon, infographics & images by Freepik and illustrations by Stories.

115 of 115

CREDITS: This presentation template was created by Slidesgo, including icons by Flaticon, infographics & images by Freepik and illustrations by Stories.