$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,
);
$first = array_first($array);
$last = array_last($array);
composer require symfony/polyfill-php85
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(...);
}
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;
}
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,
]);
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 */);
}
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(...),
) {}
// ...
}
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,
],
);
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
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),
};
};
/**
* ???
*/
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
{
// ...
}