User: support setting custom fields + array autocreation in non-existent field
authorGergő Tisza <tgr.huwiki@gmail.com>
Wed, 10 Jul 2019 18:46:21 +0000 (20:46 +0200)
committerGergő Tisza <gtisza@wikimedia.org>
Wed, 10 Jul 2019 20:35:56 +0000 (20:35 +0000)
I889924037 added a __set method which did not actually handle fields being set.
For better or worse, setting custom fields on ubiquitous objects like User is a
common form of in-process caching, so this is a B/C break; restore for now.

PHP allows creating an array in a previously non-existent object property
with $o->foo['bar'] = $val, but doesn't properly handle that on objects
which have magic getter/setter. Add an ugly hack to make it work (but warn).

Depends on I15090ae9e4b66ac25f631f6179c4394ce8c445a9.

Bug: T227688
Change-Id: I62b80ab4fa10de984cf2c879ab12d91b0fd9bc1c

includes/user/User.php

index d0d8351..cc6ef75 100644 (file)
@@ -243,10 +243,19 @@ class User implements IDBAccessObject, UserIdentity {
                return (string)$this->getName();
        }
 
-       public function __get( $name ) {
+       public function &__get( $name ) {
                // A shortcut for $mRights deprecation phase
                if ( $name === 'mRights' ) {
-                       return $this->getRights();
+                       $copy = $this->getRights();
+                       return $copy;
+               } elseif ( !property_exists( $this, $name ) ) {
+                       // T227688 - do not break $u->foo['bar'] = 1
+                       wfLogWarning( 'tried to get non-existent property' );
+                       $this->$name = null;
+                       return $this->$name;
+               } else {
+                       wfLogWarning( 'tried to get non-visible property' );
+                       return null;
                }
        }
 
@@ -258,6 +267,10 @@ class User implements IDBAccessObject, UserIdentity {
                                $this,
                                is_null( $value ) ? [] : $value
                        );
+               } elseif ( !property_exists( $this, $name ) ) {
+                       $this->$name = $value;
+               } else {
+                       wfLogWarning( 'tried to set non-visible property' );
                }
        }