Make WordPress Core


Ignore:
Timestamp:
08/03/2023 04:25:25 PM (20 months ago)
Author:
hellofromTonya
Message:

Code Modernization: Deprecate dynamic properties in WP_User_Query magic methods.

The unknown use of unknown dynamic property within the WP_User_Query 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_User_Query.

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.
  • Fixes __set() by removing the value return after setting a declared property, as (a) unnecessary and (b) __set() should return void per the PHP handbook.
  • Fixes __isset() to return false if not in the $compat_fields, as isset() and __isset() should always return bool:
  • 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 as a property on the child class. When getting its value, e.g. $user_query->data, the WP_User_Query::__get() magic method is invoked, the following deprecation notice thrown, and null returned:

The property data is not declared. Setting a dynamic property is deprecated since version 6.4.0! Instead, declare 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.

If a plugin adds a property to $compat_fields array, then sites using that plugin would experience (a) an Undefined property Warning (PHP 8) | Notice (PHP 7) and (b) a possible change in behavior.

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_User_Query. 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, #27881, #30891.

Follow-up to [15491], [28528], [31144].

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-user-query.php

    r56169 r56353  
    11101110     *
    11111111     * @since 4.0.0
     1112     * @since 6.4.0 Getting a dynamic property is deprecated.
    11121113     *
    11131114     * @param string $name Property to get.
     
    11181119            return $this->$name;
    11191120        }
     1121
     1122        trigger_error(
     1123            "The property `{$name}` is not declared. Getting a dynamic property is " .
     1124            'deprecated since version 6.4.0! Instead, declare the property on the class.',
     1125            E_USER_DEPRECATED
     1126        );
     1127        return null;
    11201128    }
    11211129
     
    11241132     *
    11251133     * @since 4.0.0
     1134     * @since 6.4.0 Setting a dynamic property is deprecated.
    11261135     *
    11271136     * @param string $name  Property to check if set.
    11281137     * @param mixed  $value Property value.
    1129      * @return mixed Newly-set property.
    11301138     */
    11311139    public function __set( $name, $value ) {
    11321140        if ( in_array( $name, $this->compat_fields, true ) ) {
    1133             return $this->$name = $value;
    1134         }
     1141            $this->$name = $value;
     1142            return;
     1143        }
     1144
     1145        trigger_error(
     1146            "The property `{$name}` is not declared. Setting a dynamic property is " .
     1147            'deprecated since version 6.4.0! Instead, declare the property on the class.',
     1148            E_USER_DEPRECATED
     1149        );
    11351150    }
    11361151
     
    11391154     *
    11401155     * @since 4.0.0
     1156     * @since 6.4.0 Checking a dynamic property is deprecated.
    11411157     *
    11421158     * @param string $name Property to check if set.
     
    11471163            return isset( $this->$name );
    11481164        }
     1165
     1166        trigger_error(
     1167            "The property `{$name}` is not declared. Checking `isset()` on a dynamic property " .
     1168            'is deprecated since version 6.4.0! Instead, declare the property on the class.',
     1169            E_USER_DEPRECATED
     1170        );
     1171        return false;
    11491172    }
    11501173
     
    11531176     *
    11541177     * @since 4.0.0
     1178     * @since 6.4.0 Unsetting a dynamic property is deprecated.
    11551179     *
    11561180     * @param string $name Property to unset.
     
    11591183        if ( in_array( $name, $this->compat_fields, true ) ) {
    11601184            unset( $this->$name );
    1161         }
     1185            return;
     1186        }
     1187
     1188        trigger_error(
     1189            "A property `{$name}` is not declared. Unsetting a dynamic property is " .
     1190            'deprecated since version 6.4.0! Instead, declare the property on the class.',
     1191            E_USER_DEPRECATED
     1192        );
    11621193    }
    11631194
Note: See TracChangeset for help on using the changeset viewer.