ProxyManager icon indicating copy to clipboard operation
ProxyManager copied to clipboard

AccessInterceptorValueHolder which proxies a parent __get triggers E_USER_NOTICE

Open arjenm opened this issue 3 years ago • 0 comments

When you generate a AccessInterceptorValueHolder proxy, a E_USER_NOTICE is always triggered when a property is not defined on the class, even if the that class has a __get-method.

This is caused by the getPublicAccessSimulationCode call here: https://github.com/Ocramius/ProxyManager/blob/dbcdf2c925c774d3521107174672665a2f0f7255/src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicGet.php#L39

And results in something like:

Notice: Undefined property: TestGet::$thisShouldNotGiveANotice in test.php on line ...

In contrast, the LazyLoadingValueHolder's __get-proxy does check for the parent and skips the call to getPublicAccessSimulationCode https://github.com/Ocramius/ProxyManager/blob/dbcdf2c925c774d3521107174672665a2f0f7255/src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicGet.php#L41

And lastly the AccessInterceptorScopeLocalizer also doesn't give a notice about a undefined property (although it does cause, "Notice: Only variables should be assigned by reference") https://github.com/Ocramius/ProxyManager/blob/dbcdf2c925c774d3521107174672665a2f0f7255/src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicGet.php#L33

Here is some test code:

use ProxyManager\Factory\AccessInterceptorScopeLocalizerFactory;
use ProxyManager\Factory\AccessInterceptorValueHolderFactory;
use ProxyManager\Factory\LazyLoadingValueHolderFactory;

error_reporting(E_ALL);

class TestGet {
    public string $notViaGet = 'not via __get';

    public function __get(string $name): string
    {
        return $name;
    }
}

// Class directly
// These don't give a notice
echo (new TestGet())->notViaGet, PHP_EOL;
echo (new TestGet())->thisShouldNotGiveANotice, PHP_EOL;

// LazyLoadingValueHolder
$lazyProxy = (new LazyLoadingValueHolderFactory())->createProxy(TestGet::class,
    function (&$wrappedObject, $proxy, $method, $parameters, &$initializer) {
        $wrappedObject = new TestGet();
        $initializer   = null;

        return true;
    }
);

// Neither do these
echo $lazyProxy->notViaGet, PHP_EOL;
echo $lazyProxy->thisShouldNotGiveANotice, PHP_EOL;

// AccessInterceptorValueHolder
$interceptorValueProxy = (new AccessInterceptorValueHolderFactory())->createProxy(
    new TestGet(),
);

// No notice
echo $interceptorValueProxy->notViaGet, PHP_EOL;
// But this one does give a notice: "Notice: Undefined property: TestGet::$thisShouldNotGiveANotice"
echo $interceptorValueProxy->thisShouldNotGiveANotice, PHP_EOL;

// AccessInterceptorScopeLocalizer
$interceptorScopeProxy = (new AccessInterceptorScopeLocalizerFactory())->createProxy(
    new TestGet(),
);

// This results in "Notice: Only variables should be assigned by reference"
echo '$interceptorScopeProxy->thisDoesNotGiveANotice', PHP_EOL;

arjenm avatar May 06 '22 13:05 arjenm