Problem/Motivation
Since PHP 7.4, doing $item[0] on an integer produces a PHP notices, creates log records, https://3v4l.org/GYsje.
Notice: Trying to access array offset on value of type int in Drupal\Core\Render\Element::property() (line 27 of /usr/local/var/www/drupal/web/core/lib/Drupal/Core/Render/Element.php)
This can happen with Drupal\Core\Render\Element::properties() where it seems common to have elements properties keys as 0, 1, 2 etc.
Steps to reproduce
Make sure to have a sample array with an integer as a key.
Example: Element::properties([0 => 'First']);
Proposed resolution
Check whether a given key is not an integer in Drupal\Core\Render\Element::property().
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #33 | 3172166-33-element-properties-php74.patch | 1.46 KB | ekes |
| #31 | 3172166-31-element-properties-php74.patch | 1.43 KB | ekes |
| #25 | revert-3172166.patch | 1.48 KB | xjm |
| #19 | 3172166-19-element-properties-php74.patch | 1.48 KB | ekes |
| #6 | 3172166-6.patch | 523 bytes | Pooja Ganjage |
Comments
Comment #2
Pooja Ganjage commentedHi,
I am applying a patch for this issue.
Kindly review the patch once.
Thanks.
Comment #3
Pooja Ganjage commentedComment #4
Pooja Ganjage commentedUploading new patch.
Comment #5
Pooja Ganjage commentedUploading new patch.
Comment #6
Pooja Ganjage commentedUploading new patch.
Comment #7
Pooja Ganjage commentedComment #8
tstoecklerNice catch, this should definitely be fixed.
Thanks for getting this started @Pooja Ganjage! I'm not sure exactly what is going wrong, but somehow you're patches cannot be applied, not sure if there's a way to assist with that.
I think similar to what was done in #3086374: Make Drupal 8 & 9 compatible with PHP 7.4 we should add an
is_int()check to the code.Also, this will need a test. Should be easy to simply add another line to
\Drupal\Tests\Core\Render\ElementTest::testChild().Comment #9
spokje@Poonja Ganjage: When I look at the latest 9.1.x-branch I see this code in
core/lib/Drupal/Core/Render/Element.php:The code in your patch is looking for this line to replace:
- return (!isset($key === '' || (0 != strpos($key, '#')));which isn't there, which makes the patch not applicable.
Not sure on what branch you created your patch, but it should be against the latest 9.1.x-branch.
Hope that helps! :)
Comment #10
megha_kundar commentedComment #11
megha_kundar commentedSorry previous applied patch was zero bytes applying updated patch
Comment #14
aklump commentedpatch #11 worked for me.
Comment #16
ekes commentedFollowing @tstoeckler suggestion in [3172166-8] Checking for is_int first. This makes sense for all possible keys passed anyway.
For the tests it is to be expected that an array passed into ::properties() could have mixed keys, so a test added there, and ::property() can just have the one key passed (from anyone doing something like properties() for example).
So attached patch updates the return to check it's not an integer first; and tests both methods. I've run tests against 9.4.x-dev. So I'll leave it at that first; but I think this will apply to 10.0.x-dev too.
Comment #17
tstoecklerThanks! Looks good to me.
Comment #18
alexpottNice find and nice test coverage!
How about
is_string($key) && $key[0] == '#'- it has less logic - the lack of the ! - and is more inline with the $key documentation. Array keys have to a string or an integer. Even floats don't work.Comment #19
ekes commented> Array keys have to a string or an integer. Even floats don't work.
Just read those casting rules. Sure there's some potential fun there - but for this it's straightforward.
Comment #20
tstoecklerThanks for the review @alexpott and the quick turnaround @ekes. Marking RTBC assuming the bot passes.
Comment #21
alexpottCommitted and pushed 60a42060171 to 10.0.x and ed0195c2bf2 to 9.4.x and 089376cf5ed to 9.3.x. Thanks!
Comment #25
xjmI believe this issue has introduced a regression on PHP 7.3:
https://www.drupal.org/pift-ci-job/2305316
Here's a patch to test the revert.
Comment #29
xjmThat fixes PHP 7.3 tests, so I've reverted it from all three branches. So, we'll need to come up with a way to make the tests pass on PHP 7.3 in Drupal 9.3 and 9.4 while still fixing the existing notice on PHP 7.4. Be sure to run tests against environments for all three PHP versions before commit. (That's always a good idea anyway for any issue where we're fixing something PHP-version-specific.) Thanks!
Comment #30
xjm...I guess I probably didn't need to revert it on 10.0.x since it requires PHP 8, but maybe there's a better way to update the test anyway. Up to whoever picks this back up. Thanks!
Comment #31
ekes commentedAdded a 7.3 test to #3172166-19: Element::properties() produces notices if given an array with integer keys but assuming that fails it will be because of
$this->assertNotContains(0, $properties);which must be some feature of assertNotContains with a (int) 0 and PHP 7.3. The code being tested runs the same from 5.4 onward https://3v4l.org/fn61KAs the
$this->assertCount(2, $properties);was also added, and the code checks for properties then containing the two expected keys, checking that the other two are not there is extraneous.So assuming above fails, this one should pass. I'll run it against 7.3. 7.4 and 8.
Comment #32
alexpottLet's replace all this with
It's simpler and works on all PHPs.
Comment #33
ekes commentedComment #34
alexpottI also think we should file a follow up to do:
The Element::child() must be the inverse of Element::property() - so let's make this true in code.
Also in Element::children() we have
if (is_int($key) || $key === '' || $key[0] !== '#') {I guess we're inlining this here for performance - which makes sense (up to a point - this stuff is called thousands of times so often the measuring makes it seem way way slower than it actually is). But regardless - we can still make this more efficient by doingif (!(is_string($key) && $key[0] !== '#')) {. We could include changing this logic in the same followup - the follow could be called something like "Align the property / child determination in Element class". Note the performance arguments forElement::child()don't really hold based on core usage.Comment #35
alexpott#33 looks great.
Comment #36
ekes commentedTests now passing on both for PHP 7.3 through 8. Follow-up posted #3262736: Align the property / child determination in Element class.
Comment #37
tstoecklerAwesome, thanks! Back to RTBC then
Comment #38
alexpottCommitted and pushed e14d16c5894 to 10.0.x and 1538662f475 to 9.4.x and e71fcde4d2c to 9.3.x. Thanks!