php must not be accessed before initialization

Why I am suddenly getting a «Typed property must not be accessed before initialization» error when introducing properties type hints?

I have updated my class definitions to make use of the newly introduced property type hints, like this:

But when trying to save my entity on Doctrine I am getting an error saying:

Typed property must not be accessed before initialization

php must not be accessed before initialization. Смотреть фото php must not be accessed before initialization. Смотреть картинку php must not be accessed before initialization. Картинка про php must not be accessed before initialization. Фото php must not be accessed before initialization

2 Answers 2

Since PHP 7.4 introduces type-hinting for properties, it is particularly important to provide valid values for all properties, so that all properties have values that match their declared types.

For the code above, if you did:

Fatal error: Uncaught Error: Typed property Foo::$val must not be accessed before initialization

The way to get around this is to assign values to all your properties that match the declared types. You can do this either as default values for the property or during construction, depending on your preference and the type of the property.

For example, for the above one could do:

Now all properties would have a valid value and the the instance would be on a valid state.

This can hit particularly often when you are relying on values that come from the DB for entity values. E.g. auto-generated IDs, or creation and/or updated values; which often are left as a DB concern.

For auto-generated IDs, the recommended way forward is to change the type declaration to:

For all the rest, just choose an appropriate value for the property’s type.

Источник

Типизированные свойства в PHP

Улучшение системы типов

Типизированные свойства классов были добавлены в PHP 7.4 и обеспечивают значительное улучшение системы типов PHP. Эти изменения полностью приняты и обратно совместимы

В этом посте мы подробно рассмотрим эту новую фичу, но сначала давайте кратко пробежимся по наиболее важным моментам:

Вот как это выглядит в действии:

Неинициализированный тип состояния

Прежде чем смотреть на так как себя ведут типизированные свойства, есть важный аспект, о котором необходимо поговорить в первую очередь.

Несмотря на то, что следующий код, на первый взгляд, вполне рабочий:

Как можно заметить из сообщения об ошибке, существует новый тип «состояния переменной»: неинициализированный.

Есть четыре важных момента, которые нужно помнить о неинициализированных состояниях:

Особенно обратите внимание, что следующий код, где неинициализируемое, ненулевое свойство устанавливается после создания объекта, является рабочим:

Хотя неинициализированное состояние проверяется только при чтении значения свойства, так же проверка типа выполняется и при записи в него. Это означает, что вы можете быть уверены, что недопустимый тип никогда не окажется в качестве значения свойства.

Значения по умолчанию и конструкторы

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

Вы можете использовать null по умолчанию, только если тип на самом деле обнуляем. Это может показаться очевидным, но есть некоторое устаревшее поведение с параметрами по умолчанию, где допускается следующее:

К счастью, такое вводящее в заблуждение поведение недопустимо для типизированных свойств.

Также обратите внимание, что невозможно иметь значения по умолчанию с object типами или классами. Вы должны использовать конструктор, чтобы установить их значения по умолчанию.

Очевидным местом для инициализации типизированных значений, конечно же, будет конструктор:

Но также помните, что я упоминал ранее: допустимо писать в неинициализированное свойство вне конструктора. Пока из свойства ничего не читается, неинициализированная проверка не выполняется.

Типы типов

Я уже упоминал, что типизированные свойства будут работать только в классах (пока), и что им нужен модификатор доступа или ключевое слово var перед ними.

Что касается доступных типов, то могут использоваться почти все типы, кроме void и callable.

Поскольку void означает отсутствие значения, имеет смысл, что его нельзя использовать для ввода значения. А вот с callable есть небольшой нюанс.

Callable в PHP может быть написан так:

Скажем, у вас будет следующий (неработающий) код:

С учетом всего написанного, вот список всех доступных типов:

Принуждаемые и строгие типы

PHP, будучи динамическим языком, за что его любят и ненавидят, будет стараться по возможности приводить или преобразовывать типы. Допустим, вы передаете строку, где ожидаете целое число, PHP попытается автоматически преобразовать эту строку:

Те же принципы применяются к типизированным свойствам. Следующий код валиден и преобразует ‘1’в 1:

Если вам не нравится это поведение, вы можете отключить его, объявив строгие типы:

Типовая дисперсия и наследование

Несмотря на то, что в PHP 7.4 появилась улучшенная дисперсия типов, типизированные свойства все еще остаются неизменными. Это означает, что следующий код будет не валиден:

Если приведенный выше пример не убедил вас, то взгляните на следующий пример:

Говоря о наследовании, вам может быть трудно найти какие-либо хорошие варианты использования для перезаписи типов унаследованных свойств.

Хотя я согласен с этим мнением, стоит отметить, что можно изменить тип унаследованного свойства, но только если модификатор доступа также изменится с private на protected или public:

Однако изменение типа с обнуляемого на ненулевое или обратное не допускается.

Еще кое-что

Как было сказано в начале этого поста, типизированные свойства являются основным дополнением к PHP. Можно еще много чего сказать о них. Я бы посоветовал вам прочитать RFC, чтобы узнать больше деталей.

Если вы еще не читали о полном списке внесенных изменений и добавленных функций в PHP 7.4, то советую незамедлительно это сделать. Честно говоря, это один из лучших релизов за последнее время, и оно того стоит!

php must not be accessed before initialization. Смотреть фото php must not be accessed before initialization. Смотреть картинку php must not be accessed before initialization. Картинка про php must not be accessed before initialization. Фото php must not be accessed before initialization

Веб-разработчик со стажем программирования более 9 лет, всегда в процессе учебы и созидания.

Источник

Typed property must not be accessed before initialization #7944

Comments

oojacoboo commented Dec 5, 2019

Bug Report

Summary

Typed property Foo::$id must not be accessed before initialization

Seems to be an issue with reflection attempting to access typed properties.

The text was updated successfully, but these errors were encountered:

We are unable to convert the task to an issue at this time. Please try again.

The issue was successfully created but we are unable to update the comment at this time.

Ocramius commented Dec 5, 2019

oojacoboo commented Dec 5, 2019 •

malarzm commented Dec 5, 2019 •

oojacoboo commented Dec 5, 2019

Yea, had a good discussion on Slack about this. I suspect that many other people will run into this issue as PHP 7.4 begins to be adopted more and people start typing their properties.

pfazzi commented Dec 6, 2019

kyrrr commented Jan 7, 2020

Would be nice to have a different solution than setting nullables everywhere.

oojacoboo commented Jan 7, 2020

@kyrrr it’s totally fixable. There is an open pull request related to this, but it seems more needs to be done on it and there hasn’t been much activity recently.

beberlei commented Jan 17, 2020

Updating doctrine/persistence to 1.3.6 will fix this issue.

leongersen commented Jan 22, 2020

I’ve filed this issue: #7999

artyom-wcd commented Mar 6, 2020 •

using this: «name»: «doctrine/persistence», «version»: «1.3.6»,
but the problem (as described before) is still there when trying to flush

oojacoboo commented Mar 6, 2020

Can the property just be unset or, by using reflection, check if nullable and optionally set as null?

Deletion is an interesting scenario. Technically, unless using soft-delete, that object shouldn’t really exist anymore, and certainly not the ID. I can see how it’d be useful to use an object after deletion though.

yapro commented Mar 19, 2020 •

VaN-dev commented Jun 23, 2020

Updating doctrine/persistence to 1.3.6 will fix this issue.

Amunak commented Aug 18, 2020 •

What about properties where you can’t set the default value, like in associations that use collection? Object cannot be a default value, and nullable makes no sense here.

And that’s not the only example, what about custom Doctrine types that use some object to hold the value?

Ocramius commented Aug 18, 2020 •

Proxy initialization does set collections?

What doesn’t work (and also didn’t work in the past) in the 2.x series is «friend objects», but otherwise proxy initialization does populate their associations.

This is the broken behavior (also pre-php-7.4):

oojacoboo commented Aug 18, 2020 •

Amunak commented Aug 18, 2020

Proxy initialization does set collections?

Interesting, for some reason I have this issue only in our Jenkins test build but can’t replicate it locally. I’ll investigate further.

Ocramius commented Aug 18, 2020

@oojacoboo yes, I made the example to show that the method call will lead to a crash: much harder to notice if I used === there 🙂

Amunak commented Aug 19, 2020

Alright, investigation concluded; when clearing cache on Jenkins no APP_ENV was defined so it cleared the default, but we needed other envs cleared. This lead to old metadata being used from cache and in those Doctrine didn’t even know about some of the fields, skipping the initialization.

Bguignard commented Jan 29, 2021 •

I had exactly the same problem, only happening on the web server and not in local environment, and the cause was :

The worst thing was, after triggering the error, I had to delete the session manually in the server in the /var/lib/php/sessions folder because Symfony couldn’t access to the session anymore which completely stuck the website for the current browser.

I first tried to «override» the __sleep() method as answered before, but even if the error was not triggered, my attribute was empty and that’s not what I wanted.

I think the heart of the problem is this __sleep() method when objects with ArrayCollection attributes are cloned from the session.

I still don’t understand why the bug didn’t happen with php 7.4.9 and 7.4.1 in a local environment but happened with 7.4.3 on the server.

The error is the same as described here but they closed it : symfony/symfony#35574

Источник

Accessing properties before initialization (PHP 7.4) #707

Comments

gjm commented Mar 12, 2020

Describe the bug

Having uninitialized typed properties in components triggers ErrorException saying typed property must not be accessed before initialization.

To Reproduce

Expected behavior
Component should be rendered successfully but an ErrorException is thrown:

Typed property Foo::$bar must not be accessed before initialization

Aditional information

When the component is constructed it calls the ensureIdPropertyIsntOverridden method which, in turn, calls the getPublicPropertiesDefinedBySubClass method in the InteractsWithProperties trait. This method tries to access the property and that triggers the error.

The text was updated successfully, but these errors were encountered:

We are unable to convert the task to an issue at this time. Please try again.

The issue was successfully created but we are unable to update the comment at this time.

basepack commented Mar 19, 2020

Can confirm this using the old @livewire(‘foo’, [‘bar’=> ‘baz’] syntax too.

tanthammar commented Apr 11, 2020

confirmed, this gives an error

setting a default value removes the error

yob-yob commented Nov 24, 2020 •

I don’t know if e89b6a1 fixed this issue for Binding Directly To Model Properties
since I’m still getting an error on ComponentConcerns/HandlesActions.php:24

Exact Error Message is
Typed property App\Http\Livewire\Courses\AddStep1::$course must not be accessed before initialization

this is how I implemented it

If Model properties are currently now supported, should we update the documentation??

basepack commented Dec 21, 2020

@yob-yob if you not pass course as a parameter I think you still have to do initialization it in the mount() method:

mokhosh commented Feb 12, 2021

NiekNijland commented Mar 23, 2021 •

mokhosh commented Mar 23, 2021

@NiekNijland 1) why are you setting it to private, you know that won’t retain state, right? 2) you don’t need to assign if that’s all you do in mount.

NiekNijland commented Mar 23, 2021 •

Livewire component’s [superadmin.customers.edit.details] public property [customerService] must be of type: [numeric, string, array, null, or boolean]. Only protected or private properties can be set as other types because JavaScript doesn’t need to access them.

Setting it to protected doesn’t change anything.

public function toggleApiAccess()
<
$this->customer[‘api_access’] ^= 1;

I’m new to livewire so I might just be overlooking something stupid.

Источник

Typed property must not be accessed before initialization #4

Comments

armpogart commented Feb 5, 2020 •

Bug Report

Summary

Cycle ORM uses the hydrator in it’s mapper while persisting entities to the database and I have encountered problem while using PHP 7.4 typed properties. Following line raises the issue as it is trying to access typed property which doesn’t have any default value (so it is not initialized by that time).

Se also original issue for reference.

How to reproduce

The text was updated successfully, but these errors were encountered:

We are unable to convert the task to an issue at this time. Please try again.

The issue was successfully created but we are unable to update the comment at this time.

kynx commented Feb 6, 2020

I’ve been bitten by the declare(strict_types=1) addition to ClassMethodsHydrator as well. Turns out I’ve been relying on the implicit coercion from the type declarations in my setter methods for database entities. Everything that hits them is a string.

I haven’t had the time to work out what to do and have locked on 2.4.2 until I do. Remove the type declarations and cast everything on assignment? Do something clever with filters? Whatever, it’s going to be a lot of work.

In general I think strict_types in a library that is designed to call end-user code is a bit too opinionated. And this is a perfect example of why. I’d be interested to hear if the maintainers would support removing them.

armpogart commented Feb 6, 2020

Xerkus commented Feb 6, 2020

@armpogart this looks kinda like implementation bug. If it is required but not initialized by the time attempt to extract data happens means inconsistent state.

Xerkus commented Feb 6, 2020

Hydrator is expected to return array of specific keys. It can’t just skip key but null is not a valid value.

In your specific example id is not available until object is persisted. That makes null a valid initial state for it:

kynx commented Feb 6, 2020

@armpogart Ack, wasn’t reading properly. Sorry to hijack!

armpogart commented Feb 6, 2020 •

If we were talking about first class strictly typed languages such as Java, or C#, I will certainly say that not initializing property is implementation problem, but I’m not sure for the PHP case.

Anyway as you said Hydrator is expected to return array of keys and I don’t see the reason for the Hydrator not to do it in case if user implementation is incorrect as the language allows it. It’s just not Hydrator’s problem I think.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *