/** * Gets the parameters array of a class method. * * @param $class The class name. * @param $method The method name. * @param $data The default values. * @return array The parameters array. */ public static function parameters($class, $method, $data = null) { $params = []; $reflexion = Inspector::inspect($class); $parameters = $reflexion->getMethod($method)->getParameters(); if ($data === null) { return $parameters; } foreach ($data as $key => $value) { $name = $key; if ($parameters) { $parameter = array_shift($parameters); $name = $parameter->getName(); } $params[$name] = $value; } foreach ($parameters as $parameter) { if ($parameter->isDefaultValueAvailable()) { $params[$parameter->getName()] = $parameter->getDefaultValue(); } } return $params; }
/** * The Constructor. * * @param mixed $reference An instance or a fully-namespaced class name. */ public function __construct($reference) { $reference = $this->_reference($reference); $isString = is_string($reference); if ($isString) { if (!class_exists($reference)) { throw new InvalidArgumentException("Can't Stub the unexisting class `{$reference}`."); } $reference = ltrim($reference, '\\'); $reflection = Inspector::inspect($reference); } else { $reflection = Inspector::inspect(get_class($reference)); } if (!$reflection->isInternal()) { $this->_reference = $reference; return; } if (!$isString) { throw new InvalidArgumentException("Can't Stub built-in PHP instances, create a test double using `Double::instance()`."); } $this->_needToBePatched = true; return $this->_reference = $reference; }
expect($param4->getName())->toBe('d'); expect($param4->getDefaultValue())->toBe(null); }); it("merges defauts values with populated values when the third argument is not empty", function () { $inspector = Inspector::parameters($this->class, 'parametersExample', ['first', 1000, true]); expect($inspector)->toBe(['a' => 'first', 'b' => 1000, 'c' => true, 'd' => null]); }); }); describe("::typehint()", function () { it("returns an empty string when no typehint is present", function () { $inspector = Inspector::parameters($this->class, 'parametersExample'); expect(Inspector::typehint($inspector[0]))->toBe(''); $inspector = Inspector::parameters($this->class, 'parameterByReference'); expect(Inspector::typehint($inspector[0]))->toBe(''); }); it("returns parameter typehint", function () { $inspector = Inspector::parameters($this->class, 'exceptionTypeHint'); $typehint = Inspector::typehint(current($inspector)); expect($typehint)->toBeA('string'); expect($typehint)->toBe('\\Exception'); $inspector = Inspector::parameters($this->class, 'arrayTypeHint'); $typehint = Inspector::typehint(current($inspector)); expect($typehint)->toBeA('string'); expect($typehint)->toBe('array'); $inspector = Inspector::parameters($this->class, 'callableTypeHint'); $typehint = Inspector::typehint(current($inspector)); expect($typehint)->toBeA('string'); expect($typehint)->toBe('callable'); }); }); });
/** * Creates a parameters signature of a `ReflectionMethod` instance. * * @param object $method A instance of `ReflectionMethod`. * @return string The parameters definition list. */ protected static function _generateSignature($method) { $params = []; $isVariadic = Suite::$PHP >= 7 ? $method->isVariadic() : false; foreach ($method->getParameters() as $num => $parameter) { $typehint = Inspector::typehint($parameter); $name = $parameter->getName(); $name = $name && $name !== '...' ? $name : 'param' . $num; $reference = $parameter->isPassedByReference() ? '&' : ''; $default = ''; if ($parameter->isDefaultValueAvailable()) { $default = var_export($parameter->getDefaultValue(), true); $default = ' = ' . preg_replace('/\\s+/', '', $default); } elseif ($parameter->isOptional()) { if ($isVariadic && $parameter->isVariadic()) { $reference = '...'; $default = ''; } else { $default = ' = NULL'; } } $typehint = $typehint ? $typehint . ' ' : $typehint; $params[] = "{$typehint}{$reference}\${$name}{$default}"; } return join(', ', $params); }
/** * Calls a registered matcher. * * @param string $name The name of the matcher. * @param array $params The parameters to pass to the matcher. * @return boolean */ public function __call($matcherName, $params) { $result = true; $spec = $this->_actual; $specification = $this->_classes['specification']; $closure = function () use($spec, $specification, $matcherName, $params, &$actual, &$result) { if ($spec instanceof $specification) { $actual = $spec->run(); if (!$spec->passed()) { return false; } } else { $actual = $spec; } array_unshift($params, $actual); $matcher = $this->_matcher($matcherName, $actual); $result = call_user_func_array($matcher . '::match', $params); return is_object($result) || $result === !$this->_not; }; try { $this->_spin($closure); } catch (TimeoutException $e) { $data['params']['timeout'] = $e->getMessage(); } finally { array_unshift($params, $actual); $matcher = $this->_matcher($matcherName, $actual); $params = Inspector::parameters($matcher, 'match', $params); $data = compact('matcherName', 'matcher', 'params'); if ($spec instanceof $specification) { foreach ($spec->logs() as $value) { $this->_logs[] = $value; } $this->_passed = $this->_passed && $spec->passed(); } } if (!is_object($result)) { $data['description'] = $data['matcher']::description(); $this->_log($result, $data); return $this; } $this->_deferred[] = $data + ['instance' => $result, 'not' => $this->_not]; return $result; }
expect(Inspector::typehint($inspector[0]))->toBe(''); }); it("returns parameter typehint", function () { $inspector = Inspector::parameters($this->class, 'exceptionTypeHint'); $typehint = Inspector::typehint(current($inspector)); expect($typehint)->toBeA('string'); expect($typehint)->toBe('\\Exception'); $inspector = Inspector::parameters($this->class, 'arrayTypeHint'); $typehint = Inspector::typehint(current($inspector)); expect($typehint)->toBeA('string'); expect($typehint)->toBe('array'); $inspector = Inspector::parameters($this->class, 'callableTypeHint'); $typehint = Inspector::typehint(current($inspector)); expect($typehint)->toBeA('string'); expect($typehint)->toBe('callable'); }); it("returns parameter typehint for scalar type hints", function () { $typehint = Inspector::typehint(new Parameter('Parameter #0 [ <required> integer $values ]')); expect($typehint)->toBeA('string'); expect($typehint)->toBe('int'); $typehint = Inspector::typehint(new Parameter('Parameter #0 [ <required> boolean $values ]')); expect($typehint)->toBeA('string'); expect($typehint)->toBe('bool'); }); it("returns empty typehint for HHVM `mixed` type hint", function () { $typehint = Inspector::typehint(new Parameter('Parameter #0 [ <required> mixed $values ]')); expect($typehint)->toBeA('string'); expect($typehint)->toBe(''); }); }); });
/** * Check the actual value can receive messages. * * @param mixed $reference An instance or a fully-namespaced class name. */ protected function _check($reference) { $isString = is_string($reference); if ($isString) { if (!class_exists($reference)) { throw new InvalidArgumentException("Can't Spy the unexisting class `{$reference}`."); } $reflection = Inspector::inspect($reference); } else { $reflection = Inspector::inspect(get_class($reference)); } if (!$reflection->isInternal()) { return; } if (!$isString) { throw new InvalidArgumentException("Can't Spy built-in PHP instances, create a test double using `Double::instance()`."); } }