php & Typed property $var must not be accessed before initialization

Пхп местами странноватый язык который странновато эволюционирует.

$a = new class {
    public readonly object $b;
    public readonly object $c;

    public function __construct() {
        $this->b = new class {
            public function helloworld() {
                return 'hello world';
            }
        };
    }
};

Вот если у нас есть объект в котором есть 2 проперти, одно из которых инициализировано, а другое нет.

С инициализированным проперти всё просто и понятно:

echo $a->b?->helloworld(); // hello world

А вот если вы так же сделаете для неинициализированного то оно умрёт:

echo $a->c?->helloworld(); // Typed property class@anonymous::$c must not be accessed before initialization

Неудобно когда умирает поэтому приходится делать дополнительную проверку:

if (isset($a->c)) {
   echo echo $a->c->helloworld();
}

Ещё более неудобно когда хочешь проверить есть ли какой-то объект и проверить что-то в этом объекте, то начинается…

if (isset($a->c) && $a->c->isValid()) {
   return true;
}

По непонятно причине ?-> умирает если оно неиницилизовано и не заменяет isset(), а вот ?? не умирает и вполне себе живёт и заменяет isset() поэтому…

echo ($a->c ?? null)?->helloworld();
if (($a->c ?? null)?->isValid()) {
   return true;
}

Какой же ад, нравится!

#php

2024.12.10 18:01

php: get property name as string

Допустим у вас есть моделька

class Model
{
    public int $id;
    public string $title;

    public function getValue(string $property): mixed
    {
        return $this->$property;
    }
}

И вам очень сильно совсем надоело хардкодить проперти и ещё больше сильнее совсем надоело их рефакторить:

$model = new Model();
$model->id = 42;
$model->title = 'my title';

$id = $model->getValue('id');
$title = $model->getValue('title');

var_dump($id, $title);

То есть преккрасное убогое решение которое поможет вам обманывать вашу IDE: автодополнение и рефакторинг работают. Но не всегда, конечно, а только в контексте исполнения.

trait PropertyNameTrait
{
    public static function __property(): object
    {
        return new class {
            public function __get(string $property): string
            {
                return $property;
            }
        };
    }

}

/** @method static Model __property() */
class Model
{
    use PropertyNameTrait;

    public int $id;
    public string $title;

    public function getValue(string $property): mixed
    {
        return $this->$property;
    }
}


$model = new Model();
$model->id = 42;
$model->title = 'my title';

$id = $model->getValue($model::__property()->id);
$title = $model->getValue(Model::__property()->title);

var_dump($id, $title);

Конечно, можно добавить ещё немного магии, но у вас не получится аккуратно чейнить __get() в трейте и классе, так что это уже по желанию (мне не очень нравится, но пользоваться этим сильно более красивее). (ну и надо не забыть кидать фатал на 404, но мне лень писать эти проверки).

/** @property-read Model $__property */
class Model
{
    public int $id;
    public string $title;

    public function getValue(string $property): mixed
    {
        return $this->$property;
    }

    public function __get(string $property): mixed
    {
        if ($property === '__property') {
            return new class {
                public function __get(string $property): string
                {
                    return $property;
                }
            };
        }
        throw new Error("404: {$property}");
    }
}

$model = new Model();
$model->id = 42;
$model->title = 'my title';

$id = $model->getValue($model->__property->id);
$title = $model->getValue($model->__property->title);

var_dump($id, $title);

#php #magic

2021.10.20 13:50

php.strict_types = 1

В похапе вводят строгую типизацию, но путь предстоит ещё крайне длинный. Судя по всему идти по нему можно будет всегда.

1. Что больше, единица или массив?

< ?php
declare(strict_types = 1);

$max = max(1, 2, ['array']);
print_r($max);
// Array
// (
//    [0] => array
// )

2. Бесконечный цикл это просто и удобно.

< ?php
declare(strict_types = 1);

for ($i = 0; $i < ['array']; $i++) {
	echo "$i.";
	if ($i === 10) { break; }
}
// 0.1.2.3.4.5.6.7.8.9.10.

Больно.

#php

2021.06.23 13:02

php autocast

Ничего нового, но до сих пор великолепно

var_dump((bool)'0'); // bool(false)
var_dump((bool)0); // bool(false)

var_dump((bool)'00'); // bool(true)
var_dump((bool)00); // bool(false)

var_dump((bool)'0x0'); // bool(true)
var_dump((bool)0x0); // bool(false)

сердечко

#php

2021.04.26 15:58

php.symfony.getCurrentUser()

Д – Дизайн

/**
 * https://github.com/symfony/symfony/blob/5.0/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php#L45-L53
 * Returns a user representation.
 *
 * @return string|object Can be a UserInterface instance, an object implementing a __toString method,
 *                       or the username as a regular string
 *
 * @see AbstractToken::setUser()
 */
public function getUser();

Н – Наслаждение

// Authorized
echo get_class($tokenStorage->getToken()->getUser());
// App\Entity\User

// Anonymous
echo $tokenStorage->getToken()->getUser();
// 'anon.'

О – Очарование

// https://github.com/symfony/symfony/blob/5.0/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php#L361-L377
protected function getUser()
{
    if (!$this->container->has('security.token_storage')) {
        throw new \LogicException('The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".');
    }

    if (null === $token = $this->container->get('security.token_storage')->getToken()) {
        return null;
    }

    if (!\is_object($user = $token->getUser())) {
        // e.g. anonymous authentication
        return null;
    }

    return $user;
}

#php #symfony #vostorg

2020.02.06 19:59

php + json-schema

Я, конечно, понимаю что уже поздновато размораживаться, но, оказывается, существует волшебная штука json-schema которой можно валидироавть структуру json’а.

Но особенно прекрасно то что оно сущетсвует для php и что ещё более прекрасно — в php оно проверяет не json, а обычный \stdClass.

То есть если вам нужно проверить структуру сложного объекта, с проверкой типов, возможностью кастинга и использованием дефолтных значений — json-scheme может спасти вам здоровье, психику и остатки волос.

И оно даже соберет все ошибки, укажет в чем проблема и даст вам путь к неправильному элементу.

  1. https://mamchenkov.net/wordpress/2017/03/11/validating-json-against-schema-in-php/
  2. https://github.com/justinrainbow/json-schema
  3. http://json-schema.org/understanding-json-schema/

#php #json #vostorg

2019.10.16 16:58