<slide title="" section="php81">

<blurb fontsize="20em" align="center">PHP 8.1</blurb>

<break lines="1" section="php81_readonly_props"/>
<blurb fontsize="1.1em" align="left">Readonly properties</blurb>
<example fontsize="1em" result='0' title="" type="php"><![CDATA[<?php
class Test {
  public readonly string $prop;

  public function __construct(string $prop) {
    $this->prop = $prop; // Initialized once in same scope
  }
}

$test = new Test("foobar");
var_dump($test->prop);
$test->prop = "foobar"; // Error
]]></example>

<break lines="1" section="php81_enums"/>
<blurb fontsize="1.1em" align="left">Enums</blurb>
<example fontsize="1em" result='0' title="" type="php"><![CDATA[<?php
enum Suit {
  case Hearts;
  case Diamonds;
  case Clubs;
  case Spades;
}

function pick_a_card(Suit $suit) { ... }
pick_a_card(Suit::Clubs); // ok
pick_a_card('Spades');    // error
]]></example>

<break lines="1" section="php81_fibers"/>
<blurb fontsize="1.1em" align="left">Fibers</blurb>
<blurb fontsize="0.9em" align="left">Full-stack interruptable functions</blurb>
<example fontsize="1em" result='0' title="" type="php"><![CDATA[<?php
use React\EventLoop\LoopInterface;
use React\Promise\PromiseInterface;

function await(PromiseInterface $promise, LoopInterface $loop): mixed {
  $fiber = Fiber::this();
  $promise->done(
    fn(mixed $value) => $loop->futureTick(fn() => $fiber->resume($value)),
    fn(Throwable $reason) => $loop->futureTick(fn() => $fiber->throw($reason))
  );

  return Fiber::suspend();
}
]]></example>

<break lines="1" section="php81_static_var_inh"/>
<blurb fontsize="1.1em" align="left">Change: Static Variable Inheritance</blurb>
<blurb fontsize="0.9em" align="left">Inherited method shares parent's static vars</blurb>
<example fontsize="1em" result='0' title="" type="php"><![CDATA[<?php
class A {
  public static function counter() {
    static $i = 0;
    return ++$i;
  }
}
class B extends A {}

echo A::counter();
echo A::counter();
echo B::counter();
echo B::counter();
// PHP 8.0 outputs 1212
// PHP 8.1 outputs 1234
]]></example>

<break lines="1" section="php81_never"/>
<blurb fontsize="1.1em" align="left">No Return type</blurb>
<example fontsize="1em" result='0' title="" type="php"><![CDATA[<?php
function redirect(string $uri): never {
  header('Location: ' . $uri);
  exit();
}

redirect('/index.html');
echo "this will never be executed!";
]]></example>

<break lines="1" section="php81_final"/>
<blurb fontsize="1.1em" align="left">final for class constants</blurb>
<example fontsize="1em" result='0' title="" type="php"><![CDATA[<?php
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
]]></example>

<break lines="1" section="php81_new_init"/>
<blurb fontsize="1.1em" align="left">new expressions can be used in initializers</blurb>
<example fontsize="1em" result='0' title="" type="php"><![CDATA[<?php
class Test {
  public function __construct(private Logger $logger = new NullLogger) {}
}

// instead of

class Test {
  private Logger $logger;

  public function __construct(?Logger $logger = null) {
        $this->logger = $logger ?? new NullLogger;
    }
}
]]></example>

<break lines="1" section="php81_first_class_callable"/>
<blurb fontsize="1.1em" align="left">First-class callables</blurb>
<example fontsize="1em" result='0' title="" type="php"><![CDATA[<?php
$fn = strlen(...);
$fn = $this->method(...)
$fn = Foo::method(...);

// instead of

$fn = Closure::fromCallable('strlen');
$fn = Closure::fromCallable([$this, 'method']);
$fn = Closure::fromCallable([Foo::class, 'method']);
]]></example>

<break lines="1" section="php81_pure_intersection"/>
<blurb fontsize="1.1em" align="left">Intersection types</blurb>
<example fontsize="1em" result='0' title="" type="php"><![CDATA[<?php
class A {
  private Traversable&Countable $countableIterator;

  public function setIterator(Traversable&Countable $countableIterator): void {
    $this->countableIterator = $countableIterator;
  }

  public function getIterator(): Traversable&Countable {
    return $this->countableIterator;
  }
}
]]></example>

<break lines="1" section="php81_misc"/>
<list>
    <bullet>Inheritance cache (avoid relinking classes)</bullet>
    <bullet>JIT improvements and add support for ARM64</bullet>
    <bullet>Optimize class name resolution</bullet>
</list>

</slide>
