Skip to content

PHP 8.1: key(), current(), next(), prev(), reset() and end() on \stdClass should not be deprecated #8688

@MircoBabin

Description

@MircoBabin

Description

The following code:

<?php

// Laravel 9 / Eloquent: DB::getSchemaBuilder()->getAllTables()
//     Executes MySql query: SHOW FULL TABLES WHERE table_type = 'BASE TABLE'
//     Returns an array of \stdClass objects using PDO.
//
// The problem is that the name of the first column is databasename dependent 'Tables_in_'+databasename. 
// e.g. If the databasename is 'tripportal' the first columnname will be 'Tables_in_tripportal'.
// Retrieving the first column value is cumbersome, because it has not a fixed name.

// https://wiki.php.net/rfc/deprecations_php_8_1
// * key(), current(), next(), prev(), and reset() on objects

function startTest($name, $func)
{
    echo PHP_EOL;
    echo '------------------------------------------------------------------------------'.PHP_EOL;
    
    echo '[BEGIN] '.$name.PHP_EOL;
    
    $func();
    
    echo '[END] '.$name.PHP_EOL;
}


$row = new \stdClass();
$row->Tables_in_tripportal = 'users';
$row->Table_type = 'BASE TABLE';

startTest('foreach', function () use ($row) {
    foreach($row as $columnName => $value) {
        echo $columnName.' => '.$value.PHP_EOL;
    }
});

startTest('key', function () use ($row) {
    $firstColumnName = key($row);
    echo $firstColumnName.PHP_EOL;
});

startTest('current', function () use ($row) {
    $firstColumnValue = current($row);
    echo $firstColumnValue.PHP_EOL;
});

startTest('reset', function () use ($row) {
    $firstColumnValue = reset($row);
    echo $firstColumnValue.PHP_EOL;
});

startTest('next', function () use ($row) {
    $firstColumnValue = reset($row);
    $secondColumnValue = next($row);
    echo $secondColumnValue.PHP_EOL;
});

startTest('end', function () use ($row) {
    $secondColumnValue = end($row);
    echo $secondColumnValue.PHP_EOL;
});

startTest('prev', function () use ($row) {
    $secondColumnValue = end($row);
    $firstColumnValue = prev($row);
    echo $firstColumnValue.PHP_EOL;
});

startTest('reset(array)', function () use ($row) {
    $firstColumnValue = reset((array)$row);
    echo $firstColumnValue.PHP_EOL;
});

Resulted in this output:


------------------------------------------------------------------------------
[BEGIN] foreach
Tables_in_tripportal => users
Table_type => BASE TABLE
[END] foreach

------------------------------------------------------------------------------
[BEGIN] key

Deprecated: key(): Calling key() on an object is deprecated in D:\Projects\Webpage\tripportals\testStdClassAsArray.php on line 38
Tables_in_tripportal
[END] key

------------------------------------------------------------------------------
[BEGIN] current

Deprecated: current(): Calling current() on an object is deprecated in D:\Projects\Webpage\tripportals\testStdClassAsArray.php on line 43
users
[END] current

------------------------------------------------------------------------------
[BEGIN] reset

Deprecated: reset(): Calling reset() on an object is deprecated in D:\Projects\Webpage\tripportals\testStdClassAsArray.php on line 48
users
[END] reset

------------------------------------------------------------------------------
[BEGIN] next

Deprecated: reset(): Calling reset() on an object is deprecated in D:\Projects\Webpage\tripportals\testStdClassAsArray.php on line 53

Deprecated: next(): Calling next() on an object is deprecated in D:\Projects\Webpage\tripportals\testStdClassAsArray.php on line 54
BASE TABLE
[END] next

------------------------------------------------------------------------------
[BEGIN] end

Deprecated: end(): Calling end() on an object is deprecated in D:\Projects\Webpage\tripportals\testStdClassAsArray.php on line 59
BASE TABLE
[END] end

------------------------------------------------------------------------------
[BEGIN] prev

Deprecated: end(): Calling end() on an object is deprecated in D:\Projects\Webpage\tripportals\testStdClassAsArray.php on line 64

Deprecated: prev(): Calling prev() on an object is deprecated in D:\Projects\Webpage\tripportals\testStdClassAsArray.php on line 65
users
[END] prev

------------------------------------------------------------------------------
[BEGIN] reset(array)

Fatal error: Uncaught Error: reset(): Argument #1 ($array) cannot be passed by reference in D:\Projects\Webpage\tripportals\testStdClassAsArray.php:70
Stack trace:
#0 D:\Projects\Webpage\tripportals\testStdClassAsArray.php(21): {closure}()
#1 D:\Projects\Webpage\tripportals\testStdClassAsArray.php(72): startTest('reset(array)', Object(Closure))
#2 {main}
  thrown in D:\Projects\Webpage\tripportals\testStdClassAsArray.php on line 70

But I expected this output instead:

No deprecation warnings about calling key(), current(), reset(), next(), end(), prev() on an object is deprecated.

I can't understand why the RFC deprecations 8.1 has not taken \stdClass into account. I believe \stdClass should be an exception. Because \stdClass and array are positioned throughout the documentation as interchangable. It is easy to cast from array to \stdClass and vice versa. And Laravel 9 with Eloquent is using \stdClass when not using models for querying the MySql database.

I had this code:

<?php
$table_name = reset($row);

And now I have to change this to:

<?php
$table_name = current((array) $row);

// NOTE: the RFC presented below alternative. But this just gives a Fatal error.
// $table_name = reset((array) $row);
// Fatal error: Uncaught Error: reset(): Argument #1 ($array) cannot be passed by reference in D:\Projects\Webpage\tripportals\testStdClassAsArray.php:70

I don't see this as an approvement of the language. Note, I'm only talking about \stdClass, not about other objects.

The RFC states:

As such, the proposal is to deprecate key(), current(), next(), prev() and reset() on objects. The suggested replacement is to cast the object to array first, or call get_mangled_object_vars(), depending on what the intention is.

But this is a false assumption, because reset((array) $row); gives a Fatal error: Uncaught Error: reset(): Argument #1 ($array) cannot be passed by reference.

PHP Version

PHP 8.1.4

Operating System

Windows/10

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions