/** * Create the mock class for the supplied definition. * * @param MockDefinition $definition The definition. * @param bool $createNew True if a new class should be created even when a compatible one exists. * * @return ReflectionClass The class. * @throws MockException If the mock generation fails. */ public function createMockClass(MockDefinition $definition, $createNew = false) { $signature = $definition->signature(); if (!$createNew) { foreach ($this->definitions as $tuple) { if ($signature === $tuple[0]) { return $tuple[1]; } } } $className = $this->generator->generateClassName($definition); if (class_exists($className, false)) { throw new ClassExistsException($className); } $source = $this->generator->generate($definition, $className); $reporting = error_reporting(E_ERROR | E_COMPILE_ERROR); $error = null; try { eval($source); } catch (ParseError $e) { $error = new MockGenerationFailedException($className, $definition, $source, error_get_last(), $e); // @codeCoverageIgnoreStart } catch (ParseException $e) { $error = new MockGenerationFailedException($className, $definition, $source, error_get_last(), $e); } catch (Throwable $error) { // re-thrown after cleanup } catch (Exception $error) { // re-thrown after cleanup } // @codeCoverageIgnoreEnd error_reporting($reporting); if ($error) { throw $error; } if (!class_exists($className, false)) { // @codeCoverageIgnoreStart throw new MockGenerationFailedException($className, $definition, $source, error_get_last()); // @codeCoverageIgnoreEnd } $class = new ReflectionClass($className); $customMethods = array(); foreach ($definition->customStaticMethods() as $methodName => $method) { $customMethods[strtolower($methodName)] = $method[0]; } foreach ($definition->customMethods() as $methodName => $method) { $customMethods[strtolower($methodName)] = $method[0]; } $customMethodsProperty = $class->getProperty('_customMethods'); $customMethodsProperty->setAccessible(true); $customMethodsProperty->setValue(null, $customMethods); $this->handleFactory->staticHandle($class); $this->definitions[] = array($signature, $class); return $class; }
/** * Generate a mock class name. * * @param MockDefinition $definition The definition. * * @return string The mock class name. */ public function generateClassName(MockDefinition $definition) { $className = $definition->className(); if (null !== $className) { return $className; } $className = 'PhonyMock'; $parentClassName = $definition->parentClassName(); if (null !== $parentClassName) { $subject = $parentClassName; } elseif ($interfaceNames = $definition->interfaceNames()) { $subject = $interfaceNames[0]; } elseif ($traitNames = $definition->traitNames()) { $subject = $traitNames[0]; } else { $subject = null; } if (null !== $subject) { $subjectAtoms = preg_split('/[_\\\\]/', $subject); $className .= '_' . array_pop($subjectAtoms); } $className .= '_' . $this->labelSequencer->next(); return $className; }
/** * Check if the supplied definition is equal to this definition. * * @return bool True if equal. */ public function isEqualTo(MockDefinition $definition) { return $definition->signature() === $this->signature; }