DDC-29: ProxyClassGenerator does not correctly override methods with type-hinted array or default values or pass by reference #36

Closed
opened 2026-01-22 12:24:57 +01:00 by admin · 2 comments
Owner

Originally created by @doctrinebot on GitHub (Oct 2, 2009).

Jira issue originally created by user itoijala:

The ProxyClassGenerator does not take into account array type-hinting, default values or pass by reference.

Example:

public function exampleMethod(array $array, &$c, $a = 'foo', array $b = array('b'))
{
    /** ... **/
}

Creates the follwing code:

public function exampleMethod($array, $c, $a, $b) 
{
    $this->_load();
    return parent::exampleMethod($array, $c, $a, $b);
}

and the following warning:

Strict Standards: Declaration of Doctrine\Generated\Proxies\Model*User_UserAProxy::exampleMethod() should be compatible with that of Model\User\User::exampleMethod() in C:\Windows\Temp\Model_User*UserAProxy.g.php on line 200

I am not sure about the consequences other than the warning when using E_STRICT.

The fix seems to be relatively simple:

Modify the _generateMethods method in ProxyClassGenerator

OLD:

private function _generateMethods(ClassMetadata $class)
    {
        $methods = '';

        foreach ($class->reflClass->getMethods() as $method) {
            if ($method->isConstructor()) {
                continue;
            }

            if ($method->isPublic() && ! $method->isFinal() && !$method->isStatic()) {
                $methods .= PHP_EOL . 'public function ' . $method->getName() . '(';
                $firstParam = true;
                $parameterString = $argumentString = '';

                foreach ($method->getParameters() as $param) {
                    if ($firstParam) {
                        $firstParam = false;
                    } else {
                        $parameterString .= ', ';
                        $argumentString  .= ', ';
                    }

                    // We need to pick the type hint class too
                    if (($paramClass = $param->getClass()) !== null) {
                        $parameterString .= '\\' . $paramClass->getName() . ' ';
                    }

                    $parameterString .= '$' . $param->getName();
                    $argumentString  .= '$' . $param->getName();
                }

                $methods .= $parameterString . ') {' . PHP_EOL;
                $methods .= '$this->*load();' . PHP*EOL;
                $methods .= 'return parent::' . $method->getName() . '(' . $argumentString . ');';
                $methods .= '}' . PHP_EOL;
            }
        }

        return $methods;
    }

NEW:

private function _generateMethods(ClassMetadata $class)
    {
        $methods = '';

        foreach ($class->reflClass->getMethods() as $method) {
            if ($method->isConstructor()) {
                continue;
            }

            if ($method->isPublic() && ! $method->isFinal() && !$method->isStatic()) {
                $methods .= PHP_EOL . 'public function ' . $method->getName() . '(';
                $firstParam = true;
                $parameterString = $argumentString = '';

                foreach ($method->getParameters() as $param) {
                    if ($firstParam) {
                        $firstParam = false;
                    } else {
                        $parameterString .= ', ';
                        $argumentString  .= ', ';
                    }

                    // We need to pick the type hint class too
                    if (($paramClass = $param->getClass()) !== null) {
                        $parameterString .= '\\' . $paramClass->getName() . ' ';
                    }
                    _* else if ($param->isArray())
                    {
                        $parameterString .= 'array ';
                    } *_

                    _* if ($param->isPassedByReference())
                    {
                        $parameterString .= '&';
                    } *_
                    $parameterString .= '$' . $param->getName();
                    _* if ($param->isDefaultValueAvailable())
                    {
                        $parameterString .= ' = ' . var_export($param->getDefaultValue(), true);
                    } *_
                    $argumentString  .= '$' . $param->getName();
                }

                $methods .= $parameterString . ') {' . PHP_EOL;
                $methods .= '$this->*load();' . PHP*EOL;
                $methods .= 'return parent::' . $method->getName() . '(' . $argumentString . ');';
                $methods .= '}' . PHP_EOL;
            }
        }

        return $methods;
    }

EDIT: forgot to add the fix for pass by reference.
EDIT2: fixed typo.

Originally created by @doctrinebot on GitHub (Oct 2, 2009). Jira issue originally created by user itoijala: The ProxyClassGenerator does not take into account array type-hinting, default values or pass by reference. Example: ``` public function exampleMethod(array $array, &$c, $a = 'foo', array $b = array('b')) { /** ... **/ } ``` Creates the follwing code: ``` public function exampleMethod($array, $c, $a, $b) { $this->_load(); return parent::exampleMethod($array, $c, $a, $b); } ``` and the following warning: ``` Strict Standards: Declaration of Doctrine\Generated\Proxies\Model*User_UserAProxy::exampleMethod() should be compatible with that of Model\User\User::exampleMethod() in C:\Windows\Temp\Model_User*UserAProxy.g.php on line 200 ``` I am not sure about the consequences other than the warning when using E_STRICT. The fix seems to be relatively simple: Modify the _generateMethods method in ProxyClassGenerator OLD: ``` private function _generateMethods(ClassMetadata $class) { $methods = ''; foreach ($class->reflClass->getMethods() as $method) { if ($method->isConstructor()) { continue; } if ($method->isPublic() && ! $method->isFinal() && !$method->isStatic()) { $methods .= PHP_EOL . 'public function ' . $method->getName() . '('; $firstParam = true; $parameterString = $argumentString = ''; foreach ($method->getParameters() as $param) { if ($firstParam) { $firstParam = false; } else { $parameterString .= ', '; $argumentString .= ', '; } // We need to pick the type hint class too if (($paramClass = $param->getClass()) !== null) { $parameterString .= '\\' . $paramClass->getName() . ' '; } $parameterString .= '$' . $param->getName(); $argumentString .= '$' . $param->getName(); } $methods .= $parameterString . ') {' . PHP_EOL; $methods .= '$this->*load();' . PHP*EOL; $methods .= 'return parent::' . $method->getName() . '(' . $argumentString . ');'; $methods .= '}' . PHP_EOL; } } return $methods; } ``` NEW: ``` private function _generateMethods(ClassMetadata $class) { $methods = ''; foreach ($class->reflClass->getMethods() as $method) { if ($method->isConstructor()) { continue; } if ($method->isPublic() && ! $method->isFinal() && !$method->isStatic()) { $methods .= PHP_EOL . 'public function ' . $method->getName() . '('; $firstParam = true; $parameterString = $argumentString = ''; foreach ($method->getParameters() as $param) { if ($firstParam) { $firstParam = false; } else { $parameterString .= ', '; $argumentString .= ', '; } // We need to pick the type hint class too if (($paramClass = $param->getClass()) !== null) { $parameterString .= '\\' . $paramClass->getName() . ' '; } _* else if ($param->isArray()) { $parameterString .= 'array '; } *_ _* if ($param->isPassedByReference()) { $parameterString .= '&'; } *_ $parameterString .= '$' . $param->getName(); _* if ($param->isDefaultValueAvailable()) { $parameterString .= ' = ' . var_export($param->getDefaultValue(), true); } *_ $argumentString .= '$' . $param->getName(); } $methods .= $parameterString . ') {' . PHP_EOL; $methods .= '$this->*load();' . PHP*EOL; $methods .= 'return parent::' . $method->getName() . '(' . $argumentString . ');'; $methods .= '}' . PHP_EOL; } } return $methods; } ``` EDIT: forgot to add the fix for pass by reference. EDIT2: fixed typo.
admin added the Bug label 2026-01-22 12:24:57 +01:00
admin closed this issue 2026-01-22 12:24:57 +01:00
Author
Owner

@doctrinebot commented on GitHub (Oct 2, 2009):

Comment created by romanb:

formatting

@doctrinebot commented on GitHub (Oct 2, 2009): Comment created by romanb: formatting
Author
Owner

@doctrinebot commented on GitHub (Oct 3, 2009):

Issue was closed with resolution "Fixed"

@doctrinebot commented on GitHub (Oct 3, 2009): Issue was closed with resolution "Fixed"
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#36