Make WordPress Core


Ignore:
Timestamp:
08/02/2023 06:35:24 PM (11 months ago)
Author:
hellofromTonya
Message:

Code Modernization: Deprecate dynamic properties in WP_List_Table magic methods.

The unknown use of unknown dynamic property within the WP_List_Table property magic methods is now deprecated. A descriptive deprecation notice is provided to alert developers to declare the property on the child class extending WP_List_Table.

Changes in this commit:

  • Adds a deprecation notice to the __get(), __set(), __isset(), __unset() magic methods, i.e. to alert and inform developers when attempting to get/set/isset/unset a dynamic property.
  • Fixes __get() to explicitly returns null when attempting to get a dynamic property.
  • Removes returning the value when setting a declared property, as (a) unnecessary and (b) __set() should return void per the PHP handbook.
  • Adds unit tests for happy and unhappy paths.

For backward compatibility, no changes are made to the internal declared properties listed in $compat_fields and accessed through the magic methods.

For example:
A child class uses a property named $data that is not declared / defined as a property on the child class. When getting its value, e.g. $list_table->data, the WP_List_Table::__get() magic method is invoked, the following deprecation notice thrown, and null returned:

The property data is not defined. Setting a dynamic (undefined) property is deprecated since version 6.4.0! Instead, define the property on the class.

Why not remove the magic methods, remove the $compat_fields property, and restore the properties public?

tl;dr Backward compatibility.

Several plugins, one of which has over 5M installs, add a property to the $compat_fields array. Removing the property would cause an Undefined property Warning (PHP 8) | Notice (PHP 7) to be thrown. Removing the associated code would change the functionality.

Why not limit the deprecation for PHP versions >= 8.2?

tl;dr original design intent and inform

The magic methods and $compat_fields property were added for one purpose: to continue providing external access to internal properties declared on WP_List_Table. They were not intended to be used for dynamic properties.

Deprecating that unintended usage both alerts developers a change is needed in their child class and informs them what to change.

References:

Related to #14579, #22234, #30891.

Follow-up to [15491], [28493], [28521], [28524], [31146].

Props antonvlasenko, jrf, markjaquith, hellofromTonya, SergeyBiryukov, desrosj, peterwilsoncc, audrasjb, costdev, oglekler, jeffpaul.
Fixes #58896.
See #56034.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-wp-list-table.php

    r56261 r56349  
    177177     *
    178178     * @since 4.0.0
     179     * @since 6.4.0 Getting a dynamic property is deprecated.
    179180     *
    180181     * @param string $name Property to get.
     
    185186            return $this->$name;
    186187        }
     188
     189        trigger_error(
     190            "The property `{$name}` is not defined. Getting a dynamic (undefined) property is " .
     191            'deprecated since version 6.4.0! Instead, define the property on the class.',
     192            E_USER_DEPRECATED
     193        );
     194        return null;
    187195    }
    188196
     
    191199     *
    192200     * @since 4.0.0
     201     * @since 6.4.0 Setting a dynamic property is deprecated.
    193202     *
    194203     * @param string $name  Property to check if set.
    195204     * @param mixed  $value Property value.
    196      * @return mixed Newly-set property.
    197205     */
    198206    public function __set( $name, $value ) {
    199207        if ( in_array( $name, $this->compat_fields, true ) ) {
    200             return $this->$name = $value;
    201         }
     208            $this->$name = $value;
     209            return;
     210        }
     211
     212        trigger_error(
     213            "The property `{$name}` is not defined. Setting a dynamic (undefined) property is " .
     214            'deprecated since version 6.4.0! Instead, define the property on the class.',
     215            E_USER_DEPRECATED
     216        );
    202217    }
    203218
     
    206221     *
    207222     * @since 4.0.0
     223     * @since 6.4.0 Checking a dynamic property is deprecated.
    208224     *
    209225     * @param string $name Property to check if set.
     
    215231        }
    216232
     233        trigger_error(
     234            "The property `{$name}` is not defined. Checking `isset()` on a dynamic (undefined) property " .
     235            'is deprecated since version 6.4.0! Instead, define the property on the class.',
     236            E_USER_DEPRECATED
     237        );
    217238        return false;
    218239    }
     
    222243     *
    223244     * @since 4.0.0
     245     * @since 6.4.0 Unsetting a dynamic property is deprecated.
    224246     *
    225247     * @param string $name Property to unset.
     
    228250        if ( in_array( $name, $this->compat_fields, true ) ) {
    229251            unset( $this->$name );
    230         }
     252            return;
     253        }
     254
     255        trigger_error(
     256            "A property `{$name}` is not defined. Unsetting a dynamic (undefined) property is " .
     257            'deprecated since version 6.4.0! Instead, define the property on the class.',
     258            E_USER_DEPRECATED
     259        );
    231260    }
    232261
Note: See TracChangeset for help on using the changeset viewer.