Problem/Motivation

See parent issue. Dynamic properties on PHP objects is going to be deprecated in the next minor and removed in the next major version of PHP requiring ResultRow to track all properties and provide storage for dynamic data.

Steps to reproduce

Test views in PHP 8.2

php8.2 ./vendor/bin/phpunit -c core core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
PHPUnit 9.5.11 by Sebastian Bergmann and contributors.

Warning:       Your XML configuration validates against a deprecated schema.
Suggestion:    Migrate your XML configuration using "--migrate-configuration"!

Testing Drupal\Tests\views\Unit\Plugin\query\SqlTest
.........                                                           9 / 9 (100%)

Time: 00:00.054, Memory: 14.00 MB

OK (9 tests, 33 assertions)

Remaining self deprecation notices (26)

  11x: Creation of dynamic property Drupal\views\ResultRow::$id is deprecated
    3x in SqlTest::testLoadEntitiesWithNoRelationshipAndNoRevision from Drupal\Tests\views\Unit\Plugin\query
    3x in SqlTest::testLoadEntitiesWithRelationship from Drupal\Tests\views\Unit\Plugin\query
    3x in SqlTest::testLoadEntitiesWithRevisionOfSameEntityType from Drupal\Tests\views\Unit\Plugin\query
    2x in SqlTest::testLoadEntitiesWithNonEntityRelationship from Drupal\Tests\views\Unit\Plugin\query

  6x: Creation of dynamic property Drupal\views\ResultRow::$entity_second__id is deprecated
    3x in SqlTest::testLoadEntitiesWithRelationship from Drupal\Tests\views\Unit\Plugin\query
    3x in SqlTest::testLoadEntitiesWithRelationshipAndRevision from Drupal\Tests\views\Unit\Plugin\query

  6x: Creation of dynamic property Drupal\views\ResultRow::$vid is deprecated
    3x in SqlTest::testLoadEntitiesWithRevision from Drupal\Tests\views\Unit\Plugin\query
    3x in SqlTest::testLoadEntitiesWithRelationshipAndRevision from Drupal\Tests\views\Unit\Plugin\query

  3x: Creation of dynamic property Drupal\views\ResultRow::$entity_first__revision__vid is deprecated
    3x in SqlTest::testLoadEntitiesWithRevisionOfSameEntityType from Drupal\Tests\views\Unit\Plugin\query

...

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Issue fork drupal-3275858

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

neclimdul created an issue. See original summary.

neclimdul’s picture

Status: Active » Needs review
StatusFileSize
new336 bytes
new2.87 KB

The simple fix is to add the attributeannotation.

I actually found this though because ResultRow can become fairly unusable in twig because properties get really weird names that aren't parse-able by twig. Twig provides a workaround but it clearly discouraging the behavior and looks like this {% set date = attribute(row, 'entity:node/field_publish_date') %}. It seems like it would make sense to have a real API with useful methods.

mondrake’s picture

Issue tags: -PHP8.2 +PHP 8.2
neclimdul’s picture

StatusFileSize
new2.87 KB
new441 bytes
new337 bytes
new364 bytes
andypost’s picture

Status: Needs review » Needs work

as there's no fixed list of properties which could be accepted the workaround looks better

+++ b/core/modules/views/src/ResultRow.php
@@ -5,6 +5,7 @@
+#[\AllowDynamicProperties]

should be enough

andypost’s picture

andypost’s picture

Filed coder's issue to allow skip attributes introduced in newer PHP version #3292573: Allow parse/ignore native attributes

andypost’s picture

Upstream issue for the attribute is https://github.com/squizlabs/PHP_CodeSniffer/issues/3489

Basically it can't be used on earlier PHP version but upstream should care about it instead of coder

andypost’s picture

andypost’s picture

andypost’s picture

PHP 8.2 alpha3 container added, queued CI run for annotation https://www.drupal.org/pift-ci-job/2420836

andypost’s picture

StatusFileSize
new912 bytes

phpstan fails https://www.drupal.org/pift-ci-job/2420734 so disabled it for testing purpose

andypost’s picture

@neclimdul at least the test from IS passed now on 8.3-alpha3 image https://dispatcher.drupalci.org/job/drupal_patches/136695/testReport/Vie...

andypost’s picture

StatusFileSize
new1.25 KB

another attempt to ignore Extension class noise as log file > 500MB

andypost’s picture

using patched version of phpstan helped (need to wait for 1.8.1 version)

andypost’s picture

andypost’s picture

Status: Needs work » Needs review

Back review as attribute patch passed

andypost’s picture

Tests still fail on timeout because we needs newer vfs package

berdir’s picture

#3299853: Apply #[\AllowDynamicProperties] attribute to base classes to make PHP 8.2 log size sane went in with this change, so this could be repurposed to actually provide a replacement API.

> Twig provides a workaround but it clearly discouraging the behavior and looks like this {% set date = attribute(row, 'entity:node/field_publish_date') %}

Fwiw, that is a search api specific thing, that will never happen with SQL queries/"standard" views. But I guess it can't be changed now, at least search_api would need to provide both the old and a normalized key for BC.

borisson_’s picture

#3299853: Apply #[\AllowDynamicProperties] attribute to base classes to make PHP 8.2 log size sane went in with this change, so this could be repurposed to actually provide a replacement API.

Does that make this change from a bug needed for 8.2 compatiblity to a task about code cleanup?

berdir’s picture

It's no longer a PHP 8.2 blocker, yes, maybe the initial problem about especially search_api identifiers being very hard to use in twig could still be a bug? But personally I'm fine to change it to change it to a task.

andypost’s picture

Status: Needs review » Needs work

now it needs real-api to remove attribute

neclimdul’s picture

Status: Needs work » Needs review
StatusFileSize
new5.95 KB
new6.37 KB

Something like this? Interdiff against the old api patch. Adds typing and update docs we can use in 10 as well as a full unit test.

andypost’s picture

Somehow it falls to pass

neclimdul’s picture

I suspect its this code in ViewResultAssertionTrait::assertIdenticalResultsetHelper

if (property_exists($value, $view_column)) {

I assume this is using property_exists so it can detect properties that are null but it can't detect magic properties like this using to provide BC. Not sure the best way to handle this but we can probably just do something in the assertion if we're clever.

andypost’s picture

Looks tests are pass now!
I think we still need BC for contrib and custom code but it could use follow-up for 11.x

andypost’s picture

StatusFileSize
new337 bytes

Here's a patch to get current baseline for failed tests

andypost’s picture

StatusFileSize
new950 bytes
new7.3 KB

Locally all tests passed so checking idea from #25

andypost’s picture

Status: Needs review » Needs work

No it has no effect except newly added test

andypost’s picture

@neclimdul any idea how to move with it?

andypost’s picture

Version: 10.0.x-dev » 10.1.x-dev
StatusFileSize
new797 bytes
new7.29 KB

let's see this way

andypost’s picture

StatusFileSize
new2.55 KB
new7.61 KB

Fix one test and ensure NULL processed via array_key_exists()

andypost’s picture

Status: Needs work » Needs review
StatusFileSize
new587 bytes
new7.65 KB

Fix CS

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative

Seems #34 had some failures.

mondrake’s picture

Assigned: Unassigned » mondrake
Related issues: +#3345938: Deprecate support for unused \PDO::FETCH_* modes

I'll give a try to this. In fact, this issue would be the major blocker for #3345938: Deprecate support for unused \PDO::FETCH_* modes. There, I'll be trying to remove usage of \PDO::FETCH_CLASS fetch mode. That mode is in fact a bit in contraddiction with the philosophy of PHP 8.2 that started tightening on usage of dynamic properties.

mondrake’s picture

StatusFileSize
new2.67 KB
mondrake’s picture

StatusFileSize
new3.88 KB
mondrake’s picture

StatusFileSize
new4.14 KB
andypost’s picture

@mondrake please elaborate why you're using stdClass instead of keyed array?

I know that this bade class allows dynamic properties but array memory usage os lowed comparing to dynamic class properties

mondrake’s picture

StatusFileSize
new5 KB
mondrake’s picture

Assigned: mondrake » Unassigned
Status: Needs work » Needs review

@andypost just because of this

+++ b/core/modules/views/src/Plugin/views/query/Sql.php
@@ -1530,13 +1530,17 @@ public function execute(ViewExecutable $view) {
-        $result->setFetchMode(\PDO::FETCH_CLASS, 'Drupal\views\ResultRow');
+        $result->setFetchMode(\PDO::FETCH_OBJ);

my motivation here is (#36)

trying to remove usage of \PDO::FETCH_CLASS fetch mode.

To me it doesn't matter array or stdClass - however I see the memory usage difference negligible.

mondrake’s picture

For the record, the RFC says about stdClass and deprecation of dynamic properties

stdClass and __get/__set are not affected by this change.

https://wiki.php.net/rfc/deprecate_dynamic_properties

mondrake’s picture

IMHO, we should postpone implementation of an API to access the row’s column values to a follow up.

Here we’re introducing usage of a storage class and magic methods to avoid dynamic properties, and it’s a full scope on its own. With this done, an API should start from deprecating the use of the magic methods.

mondrake’s picture

StatusFileSize
new7.1 KB
new2.59 KB

Added tests for the magic methods.

mondrake’s picture

StatusFileSize
new594 bytes
new7.09 KB
alexpott’s picture

+++ b/core/modules/views/src/ResultRow.php
@@ -5,9 +5,13 @@
-#[\AllowDynamicProperties]
 class ResultRow {
 
+  /**
+   * Raw row data.
+   */
+  protected \stdClass $data;

This doesn't really feel like much of a win. It feels like we're just doing this because we have `#[\AllowDynamicProperties]`. We're still ending up with a class with dynamic properties. Why not make ResultRow extend from \stdClass? And then I think we can drop the `#[\AllowDynamicProperties]` and have no other new code?

berdir’s picture

I would definitely prefer making data an array and I don't see a problem with having arbitrary keys in there. That's by design and common, content entities also have an internal $values array property. A property typed on stdClass feels weird to me.

mondrake’s picture

Status: Needs review » Needs work

#47

Why not make ResultRow extend from \stdClass?

1. that would not be sufficient to get rid of the #[\AllowDynamicProperties] attribute, see the discussion part in https://wiki.php.net/rfc/deprecate_dynamic_properties#:~:text=Discussion...

2. my motivation is #36, I would like to have a separate storage here, not added properties. No problem to switch back to array per #48.

mondrake’s picture

Assigned: Unassigned » mondrake

On this.

alexpott’s picture

FWIW @mondrake extending \stdClass would allow us to remove the attribute - see https://3v4l.org/qalMV#v8.2.3

alexpott’s picture

I wonder about the performance implications of moving to an array and away from dynamic properties on the class. PHP will have double the number of things to track. I.e. instead on 1 object you'll now have an object and an array.

mondrake’s picture

@alexpott thanks for #51 - I then misinterpreted the RFC.

#49.1 does not stand then, edited.

mondrake’s picture

Change to MR workflow. Just #46 applied to the MR.

mondrake’s picture

Assigned: mondrake » Unassigned
Status: Needs work » Needs review

Changed stdClass to array.

daffie’s picture

Status: Needs review » Reviewed & tested by the community

All the code changes look good to me.
The #[\AllowDynamicProperties] has been removed from the class.
Testing has been added.
For me it is RTBC.

berdir’s picture

This gets rid of the attribute but doesn't really address #2.

I don't quite understand why this adds hasColumn() but no other explicit methods to access the data. either we add get as well or we don't have has either? __isset() exists too? Ah, I I see, it's to replace the property exists check. Unsure about the name too.

I don't think moving to an array from undefined properties is a performance problem, if we're concerned about that then we should probably not rely on magic methods. array_key_exists() is also slower than isset(), if we're concened about performance?

mondrake’s picture

#58 for sure if someone wants to develop a full fledged API according to #2, they may do so. In any case the magic methods will have to stay (even though deprecated) till next major. I think the point is more whether to do it here or in a following issue.

My motivation here is #36, I will not pursue any of the above further.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

We're changing from if (property_exists($row, $this->aliases[$column])) { to if ($row->hasColumn($this->aliases[$column])) { - any contrib code that does this will break. As pointed out earlier dynamic properties on \stdClass are not deprecated so we're not really making a change we have to make here. So looking at contrib we'll break things see https://git.drupalcode.org/search?group_id=2&repository_ref=&scope=blobs... - plus if people are doing it in contrib then it will be done in custom code too.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

This came up as a daily BSI target.

IS needs to be updated with the proposed solution.
MR needs to be opened for 11.x and address the open threads from 3588

Thanks!

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.