Как получить первый элемент массива?

                
                    $firstKey = array_key_first($array);

                    if ($firstKey === null) {
                        $first = null;
                    } else {
                        $first = $array[$firstKey];
                    }
                
            
                
                    $first = null;

                    foreach ($array as $value) {
                        $first = $value;

                        break;
                    }
                
            
                
                    $first = reset($array);

                    if ($first === false) {
                        // $array is empty or first value is false
                    }
                
            
                
                    $first = new ArrayIterator($array)->current();
                
            
                
                    $first = array_values($array)[0] ?? null;
                
            
                
                    $first = array_shift($array);
                
            
                
                    $reversed = array_reverse($array);

                    $first = array_pop($reversed);
                
            
                
                    $first = array_reduce(
                        $array,
                        static fn($carry, $value) => $carry ?? $value,
                    );
                
            

array_first() and array_last()

                
                    $first = array_first($array);

                    $last = array_last($array);
                
            
                
                    composer require symfony/polyfill-php85
                
            

Pipe operator v3

                
                    function normalizeUsername(string $name): string
                    {
                        $name = trim($name);
                        $name = strtolower($name);
                        $name = preg_replace(T_ME_REGEX, '', $name);
                        $name = trim($name);

                        return $name;
                    }
                
            
                
                    function normalizeUsername(string $name): string
                    {
                        return $name
                            |> trim(...)
                            |> strtolower(...)
                            |> fn (string $name) => preg_replace(T_ME_REGEX, '', $name)
                            |> trim(...);
                    }
                
            
                
                    function normalizeUsername(string $name): string
                    {
                        return $name
                            |> trim(...)
                            |> strtolower(...)
                            |> fn (string $name) =>
                                preg_replace(T_ME_REGEX, '', $name)
                                    |> trim(...);
                    }
                
            
                
                    0
                        |> fn($x) => $x < 5
                        |> fn($x) => var_dump($x);
                
            
                
                    0
                        |> fn($x) => $x < (5 |> fn($x) => var_dump($x));
                
            
                
                    function normalizeUsername(string $name): string
                    {
                        return $name
                            |> trim(...)
                            |> strtolower(...)
                            // ❌ Fatal error:
                            // ❌ Arrow functions on the right hand side of |>
                            // ❌ must be parenthesized
                            |> fn (string $name) => preg_replace(T_ME_REGEX, '', $name)
                            |> trim(...);
                    }
                
            
                
                    function normalizeUsername(string $name): string
                    {
                        return $name
                            |> trim(...)
                            |> strtolower(...)
                            |> (fn (string $name) => preg_replace(T_ME_REGEX, '', $name))
                            |> trim(...);
                    }
                
            
                
                    function normalizeUsername(string $name): string
                    {
                        return $name
                            |> trim(...)
                            |> strtolower(...)
                            |> preg_replace(T_ME_REGEX, '', ?)
                            |> trim(...);
                    }
                
            

Add RFC 3986 and WHATWG URL compliant API

Exploiting URL Parsing Confusion
                
                    namespace Uri;

                    class UriException extends \Exception {}

                    class InvalidUriException extends UriException {}

                    enum UriComparisonMode
                    {
                        case IncludeFragment;
                        case ExcludeFragment;
                    }
                
            
                
                    namespace Uri\Rfc3986;

                    final readonly class Uri
                    {
                        public static function parse(string $uri, ?Uri $baseUrl = null): ?static {}

                        /** @throws Uri\InvalidUriException */
                        public function __construct(string $uri, ?Uri $baseUrl = null) {}

                        public function getScheme(): ?string {}

                        public function getRawScheme(): ?string {}

                        /** @throws Uri\InvalidUriException */
                        public function withScheme(?string $scheme): static {}

                        // ...
                    }
                
            
                
                    namespace Uri\WhatWg;

                    final readonly class Url { /** ... */ }

                    enum UrlValidationErrorType { /** cases */ }

                    final readonly class UrlValidationError
                    {
                        public function __construct(
                            public string $context,
                            public UrlValidationErrorType $type,
                            public bool $failure,
                        ) {}
                    }

                    class InvalidUrlException extends \Uri\InvalidUriException
                    {
                        /** @param list<UrlValidationError> $errors */
                        public readonly array $errors;
                    }
                
            

Clone with v2

                
                    namespace Thesis\Amqp;

                    final readonly class Message
                    {
                        public function __construct(
                            public string $body = '',
                            public array $headers = [],
                            public ?string $contentType = null,
                            public ?string $contentEncoding = null,
                            public DeliveryMode $deliveryMode = DeliveryMode::Whatever,
                            public ?int $priority = null,
                            public ?string $correlationId = null,
                            // ...
                        ) {}
                    }
                
            
                
                    return new Message(
                        body: $message->body,
                        headers: $message->headers,
                        contentType: $message->contentType,
                        contentEncoding: $message->contentEncoding,
                        deliveryMode: $message->deliveryMode,
                        priority: $message->priority,
                        correlationId: $correlationId,
                        // ...
                    );
                
            
                
                    final readonly class Message
                    {
                        // ...

                        public function withCorrelationId(?string $correlationId): self
                        {
                            return new self(
                                body: $this->body,
                                // ...
                                correlationId: $correlationId,
                                // ...
                            );
                        }
                    }

                    $message = $message->withCorrelationId('...');
                
            
                
                    final readonly class Message
                    {
                        // ...

                        public function withCorrelationId(?string $correlationId): self
                        {
                            $message = clone $this;

                            // ❌ Cannot modify readonly property
                            $message->correlationId = $correlationId;

                            return $message;
                        }
                    }

                    $message = $message->withCorrelationId('...');
                
            
                
                    final readonly class Message
                    {
                        // ...

                        public function withCorrelationId(?string $correlationId): self
                        {
                            // ✅ 🙂
                            return new self(...[
                                ...get_object_vars($this),
                                'correlationId' => $correlationId,
                            ]);
                        }
                    }

                    $message = $message->withCorrelationId('...');
                
            
                
                    final readonly class Message
                    {
                        // ...

                        public function withCorrelationId(?string $correlationId): self
                        {
                            // ✅ 🤩
                            return clone($this, [
                                'correlationId' => $correlationId,
                            ]);
                        }
                    }

                    $message = $message->withCorrelationId('...');
                
            
                
                    final readonly class Message
                    {
                        // ...
                    }

                    $message = clone(new Message(), [
                        'correlationId' => $correlationId,
                    ]);
                
            
                
                    final readonly class Message
                    {
                        // ...
                    }

                    // ❌ Cannot modify protected(set) readonly property
                    // ❌ Message::$correlationId from global scope

                    $message = clone(new Message(), [
                        'correlationId' => $correlationId,
                    ]);
                
            
Marking return values as important
(#[NoDiscard])
                
                    namespace Yiisoft\Validator;

                    interface ValidatorInterface
                    {
                        public function validate(
                            mixed $data,
                            callable|iterable|object|string|null $rules = null,
                            ?ValidationContext $context = null,
                        ): Result;
                    }
                
            
                
                    new Validator()->validate(0, new Number(min: 1));
                
            
                
                    $result = new Validator()->validate(0, new Number(min: 1));

                    // false 😲
                    dump($result->isValid());
                
            
                
                    final class Validator implements ValidatorInterface
                    {
                        // ...

                        #[\NoDiscard('Неправильно, широкую на широкую надо!!!')]
                        public function validate(/** args */): Result
                        {
                            // ...
                        }

                        // ...
                    }
                
            
                
                    // ⚠️ Warning: The return value of method
                    // ⚠️ Validator::validate() should either be used
                    // ⚠️ or intentionally ignored by casting it as (void),
                    // ⚠️ Неправильно, широкую на широкую надо!!!

                    new Validator()->validate(0, new Number(min: 1));
                
            
                
                    public function testRuleWithoutHandler(): void
                    {
                        $this->expectException(RuleHandlerNotFoundException::class);

                        $validator = new Validator();

                        // ⚠️ Warning
                        $validator->validate(/** args */);
                    }
                
            
                
                    public function testRuleWithoutHandler(): void
                    {
                        $this->expectException(RuleHandlerNotFoundException::class);

                        $validator = new Validator();

                        // ✅
                        (void) $validator->validate(/** args */);
                    }
                
            
Support Closures in
constant expressions
First Class Callables in
constant expressions
                
                    final readonly class Pay
                    {
                        public function __construct(
                            #[Assert(is_numeric(...))]
                            public string $amount,
                        ) {}
                    }
                
            
                
                    final readonly class Register
                    {
                        public function __construct(
                            #[Assert(self::isLengthy(...))]
                            public string $rawPassword,
                        ) {}

                        private static function isLengthy(string $pass): bool
                        {
                            return mb_strlen($pass) >= 8;
                        }
                    }
                
            
                
                    final readonly class Register
                    {
                        public function __construct(
                            #[Assert(static function (string $password): bool {
                                return trim($password) !== '';
                            })]
                            public string $rawPassword,
                        ) {}
                    }
                
            
                
                    final readonly class Register
                    {
                        private const Closure NON_EMPTY =
                            static function (string $password): bool {
                                return trim($password) !== '';
                            };

                        public function __construct(
                            #[Assert(self::NON_EMPTY)]
                            public string $rawPassword,
                        ) {}
                    }
                
            
                
                    const NON_EMPTY_VALIDATOR = static function (string $password): bool {
                        return trim($password) !== '';
                    };

                    final readonly class Register
                    {
                        public function __construct(
                            #[Assert(NON_EMPTY_VALIDATOR)]
                            public string $rawPassword,
                        ) {}
                    }
                
            
                
                    final readonly class Service
                    {
                        public function __construct(
                            private Closure $onFinish,
                            private LoggerInterface $logger = new NullLogger(),
                        ) {}

                        public function do(): void
                        {
                            // ...

                            ($this->onFinish)();
                        }
                    }
                
            
                
                    final readonly class Service
                    {
                        private Closure $onFinish;

                        public function __construct(
                            ?Closure $onFinish = null,
                        ) {
                            $this->onFinish = $onFinish ?? static function (): void {};
                        }

                        // ...
                    }
                
            
                
                    final readonly class Service
                    {
                        public function __construct(
                            private Closure $onFinish = static function (): void {},
                        ) {}

                        // ...
                    }
                
            
                
                    function void(): void {}

                    final readonly class Service
                    {
                        public function __construct(
                            private Closure $onFinish = void(...),
                        ) {}

                        // ...
                    }
                
            
Add persistent curl share handles Persistent curl share handle improvement
                
                    namespace Composer\Util\Http;

                    class CurlDownloader
                    {
                        public function __construct(/** args */)
                        {
                            // ...

                            $this->shareHandle = $sh = curl_share_init();
                            curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
                            curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
                            curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);

                            // ...
                        }
                    }
                
            
                
                    $db = new PDO('mysql:host=localhost;dbname=test', $user, $pass, [
                        PDO::ATTR_PERSISTENT => true
                    ]);
                
            
                
                    $shareHandle = curl_share_init_persistent(
                        share_options: [
                            CURL_LOCK_DATA_COOKIE, // ❌
                            CURL_LOCK_DATA_DNS,
                            CURL_LOCK_DATA_SSL_SESSION,
                        ],
                    );
                
            
Asymmetric Visibility
for Static Properties
                
                    final class GlobalCounter
                    {
                        public private(set) static int $current = 0;

                        public static function increment(): void
                        {
                            ++self::$current;
                        }
                    }

                    GlobalCounter::increment();
                    GlobalCounter::increment();

                    var_dump(GlobalCounter::$current); // 2
                
            
Implement Closure::getCurrent()
to retrieve current closure
                
                    function fibonacci(int $n): int
                    {
                        return match ($n) {
                            0 => 0,
                            1 => 1,
                            default => fibonacci($n - 1) + fibonacci($n - 2),
                        };
                    }
                
            
                
                    $fibonacci = static function (int $n): int {
                        return match ($n) {
                            0 => 0,
                            1 => 1,
                            default => ???($n - 1) + ???($n - 2),
                        };
                    };
                
            
                
                    $fibonacci = static function (int $n) use (&$fibonacci): int {
                        return match ($n) {
                            0 => 0,
                            1 => 1,
                            default => $fibonacci($n - 1) + $fibonacci($n - 2),
                        };
                    };
                
            
                
                    $fibonacci = static function (int $n): int {
                        $self = Closure::getCurrent();

                        return match ($n) {
                            0 => 0,
                            1 => 1,
                            default => $self($n - 1) + $self($n - 2),
                        };
                    };
                
            

Полезновое

Оцени мой доклад 🙏
Оцени доклад

@vudaltsov
Пых / Пых.конф
Thesis / Typhoon

Для тех, кто любит типы...

                
                    /**
                     * ???
                     */
                    function array_first(array $array): mixed
                    {
                        // ...
                    }
                
            
                
                    /**
                     * @template T
                     * @param array<T> $array
                     * @return ?T
                     */
                    function array_first(array $array): mixed
                    {
                        // ...
                    }
                
            
                
                    /**
                     * @template T
                     * @param array<T> $array
                     * @return ($array is non-empty-array ? T : ?T)
                     */
                    function array_first(array $array): mixed
                    {
                        // ...
                    }
                
            
                
                    /**
                     * @template T
                     * @param array<T> $array
                     * @return (
                     *     $array is array{} ? null :
                     *     $array is non-empty-array ? T :
                     *     ?T
                     * )
                     */
                    function array_first(array $array): mixed
                    {
                        // ...
                    }