You are here

Generator.php in Zircon Profile 8

File

vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator.php
View source
<?php

/*
 * This file is part of the PHPUnit_MockObject package.
 *
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
use Doctrine\Instantiator\Instantiator;
use Doctrine\Instantiator\Exception\InvalidArgumentException as InstantiatorInvalidArgumentException;
use Doctrine\Instantiator\Exception\UnexpectedValueException as InstantiatorUnexpectedValueException;
if (!function_exists('trait_exists')) {
  function trait_exists($traitname, $autoload = true) {
    return false;
  }
}

/**
 * Mock Object Code Generator
 *
 * @since Class available since Release 1.0.0
 */
class PHPUnit_Framework_MockObject_Generator {

  /**
   * @var array
   */
  private static $cache = array();

  /**
   * @var array
   */
  protected $blacklistedMethodNames = array(
    '__CLASS__' => true,
    '__DIR__' => true,
    '__FILE__' => true,
    '__FUNCTION__' => true,
    '__LINE__' => true,
    '__METHOD__' => true,
    '__NAMESPACE__' => true,
    '__TRAIT__' => true,
    '__clone' => true,
    '__halt_compiler' => true,
    'abstract' => true,
    'and' => true,
    'array' => true,
    'as' => true,
    'break' => true,
    'callable' => true,
    'case' => true,
    'catch' => true,
    'class' => true,
    'clone' => true,
    'const' => true,
    'continue' => true,
    'declare' => true,
    'default' => true,
    'die' => true,
    'do' => true,
    'echo' => true,
    'else' => true,
    'elseif' => true,
    'empty' => true,
    'enddeclare' => true,
    'endfor' => true,
    'endforeach' => true,
    'endif' => true,
    'endswitch' => true,
    'endwhile' => true,
    'eval' => true,
    'exit' => true,
    'expects' => true,
    'extends' => true,
    'final' => true,
    'for' => true,
    'foreach' => true,
    'function' => true,
    'global' => true,
    'goto' => true,
    'if' => true,
    'implements' => true,
    'include' => true,
    'include_once' => true,
    'instanceof' => true,
    'insteadof' => true,
    'interface' => true,
    'isset' => true,
    'list' => true,
    'namespace' => true,
    'new' => true,
    'or' => true,
    'print' => true,
    'private' => true,
    'protected' => true,
    'public' => true,
    'require' => true,
    'require_once' => true,
    'return' => true,
    'static' => true,
    'switch' => true,
    'throw' => true,
    'trait' => true,
    'try' => true,
    'unset' => true,
    'use' => true,
    'var' => true,
    'while' => true,
    'xor' => true,
  );

  /**
   * Returns a mock object for the specified class.
   *
   * @param  array|string                                  $type
   * @param  array                                         $methods
   * @param  array                                         $arguments
   * @param  string                                        $mockClassName
   * @param  bool                                          $callOriginalConstructor
   * @param  bool                                          $callOriginalClone
   * @param  bool                                          $callAutoload
   * @param  bool                                          $cloneArguments
   * @param  bool                                          $callOriginalMethods
   * @param  object                                        $proxyTarget
   * @return object
   * @throws InvalidArgumentException
   * @throws PHPUnit_Framework_Exception
   * @throws PHPUnit_Framework_MockObject_RuntimeException
   * @since  Method available since Release 1.0.0
   */
  public function getMock($type, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $cloneArguments = true, $callOriginalMethods = false, $proxyTarget = null) {
    if (!is_array($type) && !is_string($type)) {
      throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'array or string');
    }
    if (!is_string($mockClassName)) {
      throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'string');
    }
    if (!is_array($methods) && !is_null($methods)) {
      throw new InvalidArgumentException();
    }
    if ($type === 'Traversable' || $type === '\\Traversable') {
      $type = 'Iterator';
    }
    if (is_array($type)) {
      $type = array_unique(array_map(function ($type) {
        if ($type === 'Traversable' || $type === '\\Traversable' || $type === '\\Iterator') {
          return 'Iterator';
        }
        return $type;
      }, $type));
    }
    if (null !== $methods) {
      foreach ($methods as $method) {
        if (!preg_match('~[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*~', $method)) {
          throw new PHPUnit_Framework_Exception(sprintf('Cannot stub or mock method with invalid name "%s"', $method));
        }
      }
      if ($methods != array_unique($methods)) {
        throw new PHPUnit_Framework_MockObject_RuntimeException(sprintf('Cannot stub or mock using a method list that contains duplicates: "%s"', implode(', ', $methods)));
      }
    }
    if ($mockClassName != '' && class_exists($mockClassName, false)) {
      $reflect = new ReflectionClass($mockClassName);
      if (!$reflect
        ->implementsInterface('PHPUnit_Framework_MockObject_MockObject')) {
        throw new PHPUnit_Framework_MockObject_RuntimeException(sprintf('Class "%s" already exists.', $mockClassName));
      }
    }
    $mock = $this
      ->generate($type, $methods, $mockClassName, $callOriginalClone, $callAutoload, $cloneArguments, $callOriginalMethods);
    return $this
      ->getObject($mock['code'], $mock['mockClassName'], $type, $callOriginalConstructor, $callAutoload, $arguments, $callOriginalMethods, $proxyTarget);
  }

  /**
   * @param  string       $code
   * @param  string       $className
   * @param  array|string $type
   * @param  bool         $callOriginalConstructor
   * @param  bool         $callAutoload
   * @param  array        $arguments
   * @param  bool         $callOriginalMethods
   * @param  object       $proxyTarget
   * @return object
   */
  protected function getObject($code, $className, $type = '', $callOriginalConstructor = false, $callAutoload = false, array $arguments = array(), $callOriginalMethods = false, $proxyTarget = null) {
    $this
      ->evalClass($code, $className);
    if ($callOriginalConstructor && is_string($type) && !interface_exists($type, $callAutoload)) {
      if (count($arguments) == 0) {
        $object = new $className();
      }
      else {
        $class = new ReflectionClass($className);
        $object = $class
          ->newInstanceArgs($arguments);
      }
    }
    else {
      try {
        $instantiator = new Instantiator();
        $object = $instantiator
          ->instantiate($className);
      } catch (InstantiatorUnexpectedValueException $exception) {
        if ($exception
          ->getPrevious()) {
          $exception = $exception
            ->getPrevious();
        }
        throw new PHPUnit_Framework_MockObject_RuntimeException($exception
          ->getMessage());
      } catch (InstantiatorInvalidArgumentException $exception) {
        throw new PHPUnit_Framework_MockObject_RuntimeException($exception
          ->getMessage());
      }
    }
    if ($callOriginalMethods) {
      if (!is_object($proxyTarget)) {
        if (count($arguments) == 0) {
          $proxyTarget = new $type();
        }
        else {
          $class = new ReflectionClass($type);
          $proxyTarget = $class
            ->newInstanceArgs($arguments);
        }
      }
      $object
        ->__phpunit_setOriginalObject($proxyTarget);
    }
    return $object;
  }

  /**
   * @param string $code
   * @param string $className
   */
  protected function evalClass($code, $className) {
    if (!class_exists($className, false)) {
      eval($code);
    }
  }

  /**
   * Returns a mock object for the specified abstract class with all abstract
   * methods of the class mocked. Concrete methods to mock can be specified with
   * the last parameter
   *
   * @param  string $originalClassName
   * @param  array  $arguments
   * @param  string $mockClassName
   * @param  bool   $callOriginalConstructor
   * @param  bool   $callOriginalClone
   * @param  bool   $callAutoload
   * @param  array  $mockedMethods
   * @param  bool   $cloneArguments
   * @return object
   * @since  Method available since Release 1.0.0
   * @throws PHPUnit_Framework_MockObject_RuntimeException
   * @throws PHPUnit_Framework_Exception
   */
  public function getMockForAbstractClass($originalClassName, array $arguments = array(), $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = array(), $cloneArguments = true) {
    if (!is_string($originalClassName)) {
      throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
    }
    if (!is_string($mockClassName)) {
      throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'string');
    }
    if (class_exists($originalClassName, $callAutoload) || interface_exists($originalClassName, $callAutoload)) {
      $reflector = new ReflectionClass($originalClassName);
      $methods = $mockedMethods;
      foreach ($reflector
        ->getMethods() as $method) {
        if ($method
          ->isAbstract() && !in_array($method
          ->getName(), $methods)) {
          $methods[] = $method
            ->getName();
        }
      }
      if (empty($methods)) {
        $methods = null;
      }
      return $this
        ->getMock($originalClassName, $methods, $arguments, $mockClassName, $callOriginalConstructor, $callOriginalClone, $callAutoload, $cloneArguments);
    }
    else {
      throw new PHPUnit_Framework_MockObject_RuntimeException(sprintf('Class "%s" does not exist.', $originalClassName));
    }
  }

  /**
   * Returns a mock object for the specified trait with all abstract methods
   * of the trait mocked. Concrete methods to mock can be specified with the
   * `$mockedMethods` parameter.
   *
   * @param  string $traitName
   * @param  array  $arguments
   * @param  string $mockClassName
   * @param  bool   $callOriginalConstructor
   * @param  bool   $callOriginalClone
   * @param  bool   $callAutoload
   * @param  array  $mockedMethods
   * @param  bool   $cloneArguments
   * @return object
   * @since  Method available since Release 1.2.3
   * @throws PHPUnit_Framework_MockObject_RuntimeException
   * @throws PHPUnit_Framework_Exception
   */
  public function getMockForTrait($traitName, array $arguments = array(), $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = array(), $cloneArguments = true) {
    if (!is_string($traitName)) {
      throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
    }
    if (!is_string($mockClassName)) {
      throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'string');
    }
    if (!trait_exists($traitName, $callAutoload)) {
      throw new PHPUnit_Framework_MockObject_RuntimeException(sprintf('Trait "%s" does not exist.', $traitName));
    }
    $className = $this
      ->generateClassName($traitName, '', 'Trait_');
    $templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR;
    $classTemplate = new Text_Template($templateDir . 'trait_class.tpl');
    $classTemplate
      ->setVar(array(
      'prologue' => 'abstract ',
      'class_name' => $className['className'],
      'trait_name' => $traitName,
    ));
    $this
      ->evalClass($classTemplate
      ->render(), $className['className']);
    return $this
      ->getMockForAbstractClass($className['className'], $arguments, $mockClassName, $callOriginalConstructor, $callOriginalClone, $callAutoload, $mockedMethods, $cloneArguments);
  }

  /**
   * Returns an object for the specified trait.
   *
   * @param  string $traitName
   * @param  array  $arguments
   * @param  string $traitClassName
   * @param  bool   $callOriginalConstructor
   * @param  bool   $callOriginalClone
   * @param  bool   $callAutoload
   * @return object
   * @since  Method available since Release 1.1.0
   * @throws PHPUnit_Framework_MockObject_RuntimeException
   * @throws PHPUnit_Framework_Exception
   */
  public function getObjectForTrait($traitName, array $arguments = array(), $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true) {
    if (!is_string($traitName)) {
      throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
    }
    if (!is_string($traitClassName)) {
      throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'string');
    }
    if (!trait_exists($traitName, $callAutoload)) {
      throw new PHPUnit_Framework_MockObject_RuntimeException(sprintf('Trait "%s" does not exist.', $traitName));
    }
    $className = $this
      ->generateClassName($traitName, $traitClassName, 'Trait_');
    $templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR;
    $classTemplate = new Text_Template($templateDir . 'trait_class.tpl');
    $classTemplate
      ->setVar(array(
      'prologue' => '',
      'class_name' => $className['className'],
      'trait_name' => $traitName,
    ));
    return $this
      ->getObject($classTemplate
      ->render(), $className['className']);
  }

  /**
   * @param  array|string $type
   * @param  array        $methods
   * @param  string       $mockClassName
   * @param  bool         $callOriginalClone
   * @param  bool         $callAutoload
   * @param  bool         $cloneArguments
   * @param  bool         $callOriginalMethods
   * @return array
   */
  public function generate($type, array $methods = null, $mockClassName = '', $callOriginalClone = true, $callAutoload = true, $cloneArguments = true, $callOriginalMethods = false) {
    if (is_array($type)) {
      sort($type);
    }
    if ($mockClassName == '') {
      $key = md5(is_array($type) ? implode('_', $type) : $type . serialize($methods) . serialize($callOriginalClone) . serialize($cloneArguments) . serialize($callOriginalMethods));
      if (isset(self::$cache[$key])) {
        return self::$cache[$key];
      }
    }
    $mock = $this
      ->generateMock($type, $methods, $mockClassName, $callOriginalClone, $callAutoload, $cloneArguments, $callOriginalMethods);
    if (isset($key)) {
      self::$cache[$key] = $mock;
    }
    return $mock;
  }

  /**
   * @param  string                                        $wsdlFile
   * @param  string                                        $className
   * @param  array                                         $methods
   * @param  array                                         $options
   * @return string
   * @throws PHPUnit_Framework_MockObject_RuntimeException
   */
  public function generateClassFromWsdl($wsdlFile, $className, array $methods = array(), array $options = array()) {
    if (!extension_loaded('soap')) {
      throw new PHPUnit_Framework_MockObject_RuntimeException('The SOAP extension is required to generate a mock object from WSDL.');
    }
    $options = array_merge($options, array(
      'cache_wsdl' => WSDL_CACHE_NONE,
    ));
    $client = new SoapClient($wsdlFile, $options);
    $_methods = array_unique($client
      ->__getFunctions());
    unset($client);
    sort($_methods);
    $templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR;
    $methodTemplate = new Text_Template($templateDir . 'wsdl_method.tpl');
    $methodsBuffer = '';
    foreach ($_methods as $method) {
      $nameStart = strpos($method, ' ') + 1;
      $nameEnd = strpos($method, '(');
      $name = substr($method, $nameStart, $nameEnd - $nameStart);
      if (empty($methods) || in_array($name, $methods)) {
        $args = explode(',', substr($method, $nameEnd + 1, strpos($method, ')') - $nameEnd - 1));
        $numArgs = count($args);
        for ($i = 0; $i < $numArgs; $i++) {
          $args[$i] = substr($args[$i], strpos($args[$i], '$'));
        }
        $methodTemplate
          ->setVar(array(
          'method_name' => $name,
          'arguments' => implode(', ', $args),
        ));
        $methodsBuffer .= $methodTemplate
          ->render();
      }
    }
    $optionsBuffer = 'array(';
    foreach ($options as $key => $value) {
      $optionsBuffer .= $key . ' => ' . $value;
    }
    $optionsBuffer .= ')';
    $classTemplate = new Text_Template($templateDir . 'wsdl_class.tpl');
    $namespace = '';
    if (strpos($className, '\\') !== false) {
      $parts = explode('\\', $className);
      $className = array_pop($parts);
      $namespace = 'namespace ' . implode('\\', $parts) . ';' . "\n\n";
    }
    $classTemplate
      ->setVar(array(
      'namespace' => $namespace,
      'class_name' => $className,
      'wsdl' => $wsdlFile,
      'options' => $optionsBuffer,
      'methods' => $methodsBuffer,
    ));
    return $classTemplate
      ->render();
  }

  /**
   * @param  array|string                $type
   * @param  array|null                  $methods
   * @param  string                      $mockClassName
   * @param  bool                        $callOriginalClone
   * @param  bool                        $callAutoload
   * @param  bool                        $cloneArguments
   * @param  bool                        $callOriginalMethods
   * @return array
   * @throws PHPUnit_Framework_Exception
   */
  protected function generateMock($type, $methods, $mockClassName, $callOriginalClone, $callAutoload, $cloneArguments, $callOriginalMethods) {
    $templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR;
    $classTemplate = new Text_Template($templateDir . 'mocked_class.tpl');
    $additionalInterfaces = array();
    $cloneTemplate = '';
    $isClass = false;
    $isInterface = false;
    $mockClassName = $this
      ->generateClassName($type, $mockClassName, 'Mock_');
    if (is_array($type)) {
      foreach ($type as $_type) {
        if (!interface_exists($_type, $callAutoload)) {
          throw new PHPUnit_Framework_Exception(sprintf('Interface "%s" does not exist.', $_type));
        }
        $additionalInterfaces[] = $_type;
        foreach ($this
          ->getClassMethods($_type) as $method) {
          if (in_array($method, $methods)) {
            throw new PHPUnit_Framework_Exception(sprintf('Duplicate method "%s" not allowed.', $method));
          }
          $methods[] = $method;
        }
      }
    }
    if (class_exists($mockClassName['fullClassName'], $callAutoload)) {
      $isClass = true;
    }
    else {
      if (interface_exists($mockClassName['fullClassName'], $callAutoload)) {
        $isInterface = true;
      }
    }
    if (!class_exists($mockClassName['fullClassName'], $callAutoload) && !interface_exists($mockClassName['fullClassName'], $callAutoload)) {
      $prologue = 'class ' . $mockClassName['originalClassName'] . "\n{\n}\n\n";
      if (!empty($mockClassName['namespaceName'])) {
        $prologue = 'namespace ' . $mockClassName['namespaceName'] . " {\n\n" . $prologue . "}\n\n" . "namespace {\n\n";
        $epilogue = "\n\n}";
      }
      $cloneTemplate = new Text_Template($templateDir . 'mocked_clone.tpl');
    }
    else {
      $class = new ReflectionClass($mockClassName['fullClassName']);
      if ($class
        ->isFinal()) {
        throw new PHPUnit_Framework_Exception(sprintf('Class "%s" is declared "final" and cannot be mocked.', $mockClassName['fullClassName']));
      }
      if ($class
        ->hasMethod('__clone')) {
        $cloneMethod = $class
          ->getMethod('__clone');
        if (!$cloneMethod
          ->isFinal()) {
          if ($callOriginalClone && !$isInterface) {
            $cloneTemplate = new Text_Template($templateDir . 'unmocked_clone.tpl');
          }
          else {
            $cloneTemplate = new Text_Template($templateDir . 'mocked_clone.tpl');
          }
        }
      }
      else {
        $cloneTemplate = new Text_Template($templateDir . 'mocked_clone.tpl');
      }
    }
    if (is_object($cloneTemplate)) {
      $cloneTemplate = $cloneTemplate
        ->render();
    }
    if (is_array($methods) && empty($methods) && ($isClass || $isInterface)) {
      $methods = $this
        ->getClassMethods($mockClassName['fullClassName']);
    }
    if (!is_array($methods)) {
      $methods = array();
    }
    $mockedMethods = '';
    if (isset($class)) {

      // https://github.com/sebastianbergmann/phpunit-mock-objects/issues/103
      if ($isInterface && $class
        ->implementsInterface('Traversable') && !$class
        ->implementsInterface('Iterator') && !$class
        ->implementsInterface('IteratorAggregate')) {
        $additionalInterfaces[] = 'Iterator';
        $methods = array_merge($methods, $this
          ->getClassMethods('Iterator'));
      }
      foreach ($methods as $methodName) {
        try {
          $method = $class
            ->getMethod($methodName);
          if ($this
            ->canMockMethod($method)) {
            $mockedMethods .= $this
              ->generateMockedMethodDefinitionFromExisting($templateDir, $method, $cloneArguments, $callOriginalMethods);
          }
        } catch (ReflectionException $e) {
          $mockedMethods .= $this
            ->generateMockedMethodDefinition($templateDir, $mockClassName['fullClassName'], $methodName, $cloneArguments);
        }
      }
    }
    else {
      foreach ($methods as $methodName) {
        $mockedMethods .= $this
          ->generateMockedMethodDefinition($templateDir, $mockClassName['fullClassName'], $methodName, $cloneArguments);
      }
    }
    $method = '';
    if (!in_array('method', $methods)) {
      $methodTemplate = new Text_Template($templateDir . 'mocked_class_method.tpl');
      $method = $methodTemplate
        ->render();
    }
    $classTemplate
      ->setVar(array(
      'prologue' => isset($prologue) ? $prologue : '',
      'epilogue' => isset($epilogue) ? $epilogue : '',
      'class_declaration' => $this
        ->generateMockClassDeclaration($mockClassName, $isInterface, $additionalInterfaces),
      'clone' => $cloneTemplate,
      'mock_class_name' => $mockClassName['className'],
      'mocked_methods' => $mockedMethods,
      'method' => $method,
    ));
    return array(
      'code' => $classTemplate
        ->render(),
      'mockClassName' => $mockClassName['className'],
    );
  }

  /**
   * @param  array|string $type
   * @param  string       $className
   * @param  string       $prefix
   * @return array
   */
  protected function generateClassName($type, $className, $prefix) {
    if (is_array($type)) {
      $type = implode('_', $type);
    }
    if ($type[0] == '\\') {
      $type = substr($type, 1);
    }
    $classNameParts = explode('\\', $type);
    if (count($classNameParts) > 1) {
      $type = array_pop($classNameParts);
      $namespaceName = implode('\\', $classNameParts);
      $fullClassName = $namespaceName . '\\' . $type;
    }
    else {
      $namespaceName = '';
      $fullClassName = $type;
    }
    if ($className == '') {
      do {
        $className = $prefix . $type . '_' . substr(md5(microtime()), 0, 8);
      } while (class_exists($className, false));
    }
    return array(
      'className' => $className,
      'originalClassName' => $type,
      'fullClassName' => $fullClassName,
      'namespaceName' => $namespaceName,
    );
  }

  /**
   * @param  array $mockClassName
   * @param  bool  $isInterface
   * @param  array $additionalInterfaces
   * @return array
   */
  protected function generateMockClassDeclaration(array $mockClassName, $isInterface, array $additionalInterfaces = array()) {
    $buffer = 'class ';
    $additionalInterfaces[] = 'PHPUnit_Framework_MockObject_MockObject';
    $interfaces = implode(', ', $additionalInterfaces);
    if ($isInterface) {
      $buffer .= sprintf('%s implements %s', $mockClassName['className'], $interfaces);
      if (!in_array($mockClassName['originalClassName'], $additionalInterfaces)) {
        $buffer .= ', ';
        if (!empty($mockClassName['namespaceName'])) {
          $buffer .= $mockClassName['namespaceName'] . '\\';
        }
        $buffer .= $mockClassName['originalClassName'];
      }
    }
    else {
      $buffer .= sprintf('%s extends %s%s implements %s', $mockClassName['className'], !empty($mockClassName['namespaceName']) ? $mockClassName['namespaceName'] . '\\' : '', $mockClassName['originalClassName'], $interfaces);
    }
    return $buffer;
  }

  /**
   * @param  string           $templateDir
   * @param  ReflectionMethod $method
   * @param  bool             $cloneArguments
   * @param  bool             $callOriginalMethods
   * @return string
   */
  protected function generateMockedMethodDefinitionFromExisting($templateDir, ReflectionMethod $method, $cloneArguments, $callOriginalMethods) {
    if ($method
      ->isPrivate()) {
      $modifier = 'private';
    }
    elseif ($method
      ->isProtected()) {
      $modifier = 'protected';
    }
    else {
      $modifier = 'public';
    }
    if ($method
      ->isStatic()) {
      $modifier .= ' static';
    }
    if ($method
      ->returnsReference()) {
      $reference = '&';
    }
    else {
      $reference = '';
    }
    return $this
      ->generateMockedMethodDefinition($templateDir, $method
      ->getDeclaringClass()
      ->getName(), $method
      ->getName(), $cloneArguments, $modifier, $this
      ->getMethodParameters($method), $this
      ->getMethodParameters($method, true), $reference, $callOriginalMethods, $method
      ->isStatic());
  }

  /**
   * @param  string $templateDir
   * @param  string $className
   * @param  string $methodName
   * @param  bool   $cloneArguments
   * @param  string $modifier
   * @param  string $arguments_decl
   * @param  string $arguments_call
   * @param  string $reference
   * @param  bool   $callOriginalMethods
   * @param  bool   $static
   * @return string
   */
  protected function generateMockedMethodDefinition($templateDir, $className, $methodName, $cloneArguments = true, $modifier = 'public', $arguments_decl = '', $arguments_call = '', $reference = '', $callOriginalMethods = false, $static = false) {
    if ($static) {
      $templateFile = 'mocked_static_method.tpl';
    }
    else {
      $templateFile = sprintf('%s_method.tpl', $callOriginalMethods ? 'proxied' : 'mocked');
    }
    $template = new Text_Template($templateDir . $templateFile);
    $template
      ->setVar(array(
      'arguments_decl' => $arguments_decl,
      'arguments_call' => $arguments_call,
      'arguments_count' => !empty($arguments_call) ? count(explode(',', $arguments_call)) : 0,
      'class_name' => $className,
      'method_name' => $methodName,
      'modifier' => $modifier,
      'reference' => $reference,
      'clone_arguments' => $cloneArguments ? 'TRUE' : 'FALSE',
    ));
    return $template
      ->render();
  }

  /**
   * @param  ReflectionMethod $method
   * @return bool
   */
  protected function canMockMethod(ReflectionMethod $method) {
    if ($method
      ->isConstructor() || $method
      ->isFinal() || $method
      ->isPrivate() || isset($this->blacklistedMethodNames[$method
      ->getName()])) {
      return false;
    }
    return true;
  }

  /**
   * Returns the parameters of a function or method.
   *
   * @param  ReflectionMethod                              $method
   * @param  bool                                          $forCall
   * @return string
   * @throws PHPUnit_Framework_MockObject_RuntimeException
   * @since  Method available since Release 2.0.0
   */
  protected function getMethodParameters(ReflectionMethod $method, $forCall = false) {
    $parameters = array();
    foreach ($method
      ->getParameters() as $i => $parameter) {
      $name = '$' . $parameter
        ->getName();

      /* Note: PHP extensions may use empty names for reference arguments
       * or "..." for methods taking a variable number of arguments.
       */
      if ($name === '$' || $name === '$...') {
        $name = '$arg' . $i;
      }
      if ($this
        ->isVariadic($parameter)) {
        if ($forCall) {
          continue;
        }
        else {
          $name = '...' . $name;
        }
      }
      $default = '';
      $reference = '';
      $typeDeclaration = '';
      if (!$forCall) {
        if ($this
          ->hasType($parameter)) {
          $typeDeclaration = (string) $parameter
            ->getType() . ' ';
        }
        elseif ($parameter
          ->isArray()) {
          $typeDeclaration = 'array ';
        }
        elseif ((defined('HHVM_VERSION') || version_compare(PHP_VERSION, '5.4.0', '>=')) && $parameter
          ->isCallable()) {
          $typeDeclaration = 'callable ';
        }
        else {
          try {
            $class = $parameter
              ->getClass();
          } catch (ReflectionException $e) {
            throw new PHPUnit_Framework_MockObject_RuntimeException(sprintf('Cannot mock %s::%s() because a class or ' . 'interface used in the signature is not loaded', $method
              ->getDeclaringClass()
              ->getName(), $method
              ->getName()), 0, $e);
          }
          if ($class !== null) {
            $typeDeclaration = $class
              ->getName() . ' ';
          }
        }
        if (!$this
          ->isVariadic($parameter)) {
          if ($parameter
            ->isDefaultValueAvailable()) {
            $value = $parameter
              ->getDefaultValue();
            $default = ' = ' . var_export($value, true);
          }
          elseif ($parameter
            ->isOptional()) {
            $default = ' = null';
          }
        }
      }
      if ($parameter
        ->isPassedByReference()) {
        $reference = '&';
      }
      $parameters[] = $typeDeclaration . $reference . $name . $default;
    }
    return implode(', ', $parameters);
  }

  /**
   * @param  ReflectionParameter $parameter
   * @return bool
   * @since  Method available since Release 2.2.1
   */
  private function isVariadic(ReflectionParameter $parameter) {
    return method_exists('ReflectionParameter', 'isVariadic') && $parameter
      ->isVariadic();
  }

  /**
   * @param  ReflectionParameter $parameter
   * @return bool
   * @since  Method available since Release 2.3.4
   */
  private function hasType(ReflectionParameter $parameter) {
    return method_exists('ReflectionParameter', 'hasType') && $parameter
      ->hasType();
  }

  /**
   * @param  string $className
   * @return array
   * @since  Method available since Release 2.3.2
   */
  private function getClassMethods($className) {
    $class = new ReflectionClass($className);
    $methods = array();
    foreach ($class
      ->getMethods() as $method) {
      if (($method
        ->isPublic() || $method
        ->isAbstract()) && !in_array($method
        ->getName(), $methods)) {
        $methods[] = $method
          ->getName();
      }
    }
    return $methods;
  }

}

Classes

Namesort descending Description
PHPUnit_Framework_MockObject_Generator Mock Object Code Generator