Add StubObject::unstub, and use it for $wgAuth->getUserInstance()
authorBrad Jorsch <bjorsch@wikimedia.org>
Wed, 11 Sep 2013 19:55:15 +0000 (12:55 -0700)
committerBrad Jorsch <bjorsch@wikimedia.org>
Wed, 11 Sep 2013 20:11:20 +0000 (13:11 -0700)
PHP's __call magic method can't handle functions with reference
parameters correctly,[1] which means that we need to manually unstub
StubObjects before calling such a method. Or you could use call-time
pass by reference with call_user_func_array, which is rather backwards
and verbose.

This change adds a convenience function to do this, and applies it to
the two calls which brought it to my attention.

[1]: https://bugs.php.net/bug.php?id=40694,
https://bugs.php.net/bug.php?id=62455

Change-Id: I74a0c04bf358e164f753b82fbefbd6205d9b2451

includes/StubObject.php
includes/User.php

index 59238fa..a3970f3 100644 (file)
  * their associated module code by deferring initialisation until the first
  * method call.
  *
+ * Note on reference parameters:
+ *
+ * If the called method takes any parameters by reference, the __call magic
+ * here won't work correctly. The solution is to unstub the object before
+ * calling the method.
+ *
  * Note on unstub loops:
  *
  * Unstub loops (infinite recursion) sometimes occur when a constructor calls
@@ -63,6 +69,20 @@ class StubObject {
                return is_object( $obj ) && !$obj instanceof StubObject;
        }
 
+       /**
+        * Unstubs an object, if it is a stub object. Can be used to break a
+        * infinite loop when unstubbing an object or to avoid reference parameter
+        * breakage.
+        *
+        * @param $obj Object to check.
+        * @return void
+        */
+       static function unstub( $obj ) {
+               if ( $obj instanceof StubObject ) {
+                       $obj->_unstub( 'unstub', 3 );
+               }
+       }
+
        /**
         * Function called if any function exists with that name in this object.
         * It is used to unstub the object. Only used internally, PHP will call
index 560c5dc..60efc9d 100644 (file)
@@ -1700,6 +1700,7 @@ class User {
                        return $this->mLocked;
                }
                global $wgAuth;
+               StubObject::unstub( $wgAuth );
                $authUser = $wgAuth->getUserInstance( $this );
                $this->mLocked = (bool)$authUser->isLocked();
                return $this->mLocked;
@@ -1717,6 +1718,7 @@ class User {
                $this->getBlockedStatus();
                if ( !$this->mHideName ) {
                        global $wgAuth;
+                       StubObject::unstub( $wgAuth );
                        $authUser = $wgAuth->getUserInstance( $this );
                        $this->mHideName = (bool)$authUser->isHidden();
                }