Make WordPress Core

09/07/2022 03:59:16 PM (22 months ago)

Tests: Correct magic methods in Basic_Object.

This is a test fixture (dummy class only used in a test context), which incorrectly implements the magic methods.

With the deprecation of dynamic properties in PHP 8.2, this needs to be fixed.

The new implementation represents a “proper” implementation of the magic methods for a class without non-public or typed properties.


  • Instead of relying on dynamic properties, the magic methods now store properties in a private $arbitrary_props array and retrieve them from there as well.
  • The original $foo property, even though declared as private, was never private in practice due to the way the magic methods were originally implemented. In effect, it was fully publicly retrievable and modifiable without any (type) restrictions. With that in mind, the foo property has been moved into the $arbitrary_props array to keep the implementation of the magic methods as clean and straightforward as possible. With the adjusted magic methods, access to and modification of $foo will (on the surface) continue to work in the same way as before, while under the hood, it is no longer affected by the dynamic properties deprecation.
  • Take note of the use of array_key_exists() instead of isset() in the __get() method. This is intentional and allows for null values to be stored and retrieved.
  • Also take note of __set() method no longer returning. __set() is supposed to be a void method. In practice, the return value would always be ignored due to how PHP handles magic methods, so in effect, this change will not make any difference and does not constitute a backward compatibility break.

    The return value of __set() is ignored because of the way PHP processes the assignment operator.

Alternatives considered:

  • Instead of fixing the magic methods, they could have been removed instead and the class be made to extend stdClass. It has been chosen not to do so for two reasons:
    1. It’s kind of nice to have at least one correct implementation of magic methods in WP, which can be used as an example to point to as well.
    2. Extending stdClass would change the class hierarchy, which may or may not affect the tests using this fixture (depending on what’s being done with the class). Extending stdClass would also obfuscate what’s going on in the class and would require extensive documentation to prevent the extension being inadvertently removed at a future point in time.
  • Instead of fixing the magic methods, the test fixture could have been deprecated and/or removed, with the few tests which use the fixture being updated to use stdClass for their test fixture instead. It has been chosen not to do so as there may well be external (plugin/theme) tests relying on this test fixture and evaluating whether that is so would be hard, as WP Directory cannot be used, since test code is normally not included in the code published on Also note, there is still a (deprecated) Basic_Subclass fixture in the test suite, which extends this class.

These magic methods and the Basic_Object test fixture were originally introduced in [28480] and [28523]. The fixture was deprecated in [42381] and undeprecated again in [45807].

At this time, the test fixture is used in the WP_Test_REST_Post_Meta_Fields and the Tests_REST_API test classes.


Follow-up to [28480], [28493], [28523], [42381], [45807].

Props jrf, costdev.
See #56514.

1 edited


  • trunk/tests/phpunit/includes/class-basic-object.php

    r46586 r54095  
    1414 */
    1515class Basic_Object {
    16     private $foo = 'bar';
     17    private $arbitrary_props = array(
     18        'foo' => 'bar',
     19    );
    1821    public function __get( $name ) {
    19         return $this->$name;
     22        if ( array_key_exists( $name, $this->arbitrary_props ) ) {
     23            return $this->arbitrary_props[ $name ];
     24        }
     26        return null;
    2027    }
    2229    public function __set( $name, $value ) {
    23         return $this->$name = $value;
     30        $this->arbitrary_props[ $name ] = $value;
    2431    }
    2633    public function __isset( $name ) {
    27         return isset( $this->$name );
     34        return isset( $this->arbitrary_props[ $name ] );
    2835    }
    3037    public function __unset( $name ) {
    31         unset( $this->$name );
     38        unset( $this->arbitrary_props[ $name ] );
    3239    }
Note: See TracChangeset for help on using the changeset viewer.