/** * @return ConcreteMethod */ protected function generateCallMethod() { $this->typeCheck->generateCallMethod(func_get_args()); $method = new ConcreteMethod(new Identifier('__call'), AccessModifier::PUBLIC_()); $method->addParameter(new Parameter(new Identifier('name'))); $method->addParameter(new Parameter(new Identifier('arguments'), new ArrayTypeHint())); return $method; }
/** * @return ConcreteMethod */ protected function generateExpectedTypeMethod() { $this->typeCheck->generateExpectedTypeMethod(func_get_args()); $expectedTypeIdentifier = new Identifier('expectedType'); $method = new ConcreteMethod($expectedTypeIdentifier, AccessModifier::PUBLIC_()); $method->statementBlock()->add(new ReturnStatement(new Member(new Variable(new Identifier('this')), new Constant($expectedTypeIdentifier)))); return $method; }
/** * @return ConcreteMethod */ protected function generateStreamTypeMethod() { $this->typeCheck->generateStreamTypeMethod(func_get_args()); $valueIdentifier = new Identifier('value'); $valueVariable = new Variable($valueIdentifier); $metaDataVariable = new Variable(new Identifier('metaData')); $metaDataModeSubscript = new Subscript($metaDataVariable, new Literal('mode')); $readableVariable = new Variable(new Identifier('readable')); $writableVariable = new Variable(new Identifier('writable')); $method = new ConcreteMethod(new Identifier('streamType'), AccessModifier::PROTECTED_()); $method->addParameter(new Parameter($valueIdentifier)); $streamGetMetaDataCall = new Call(QualifiedIdentifier::fromString('\\stream_get_meta_data')); $streamGetMetaDataCall->add($valueVariable); $method->statementBlock()->add(new ExpressionStatement(new Assign($metaDataVariable, $streamGetMetaDataCall))); $readablePregMatchCall = new Call(QualifiedIdentifier::fromString('\\preg_match')); $readablePregMatchCall->add(new Literal('/[r+]/')); $readablePregMatchCall->add($metaDataModeSubscript); $readableIf = new IfStatement($readablePregMatchCall, new StatementBlock(), new StatementBlock()); $readableIf->trueBranch()->add(new ExpressionStatement(new Assign($readableVariable, new Literal('true')))); $readableIf->falseBranch()->add(new ExpressionStatement(new Assign($readableVariable, new Literal('false')))); $method->statementBlock()->add($readableIf); $writablePregMatchCall = new Call(QualifiedIdentifier::fromString('\\preg_match')); $writablePregMatchCall->add(new Literal('/[waxc+]/')); $writablePregMatchCall->add($metaDataModeSubscript); $writableIf = new IfStatement($writablePregMatchCall, new StatementBlock(), new StatementBlock()); $writableIf->trueBranch()->add(new ExpressionStatement(new Assign($writableVariable, new Literal('true')))); $writableIf->falseBranch()->add(new ExpressionStatement(new Assign($writableVariable, new Literal('false')))); $method->statementBlock()->add($writableIf); $sprintfCall = new Call(QualifiedIdentifier::fromString('\\sprintf')); $sprintfCall->add(new Literal('stream {readable: %s, writable: %s}')); $sprintfCall->add($readableVariable); $sprintfCall->add($writableVariable); $method->statementBlock()->add(new ReturnStatement($sprintfCall)); return $method; }
/** * @param Configuration $configuration * @param ClassDefinition $classDefinition * @param ClassName $facadeClassName * @param array<Issue\IssueInterface> &$issues */ protected function analyzeClass(Configuration $configuration, ClassDefinition $classDefinition, ClassName $facadeClassName, array &$issues) { $this->typeCheck->analyzeClass(func_get_args()); $expectedfacadeClassName = $classDefinition->classNameResolver()->shorten($facadeClassName); $hasConstructorInit = false; $propertyName = 'typeCheck'; $hasNonStaticCalls = false; if ($classDefinition->hasMethod('__construct')) { $methodDefinition = $classDefinition->method('__construct'); if ($this->methodHasInit($methodDefinition, $expectedfacadeClassName, $propertyName)) { $hasConstructorInit = true; } elseif (!$this->methodHasConstructorStaticCall($methodDefinition, $expectedfacadeClassName)) { $issues[] = new Issue\ClassIssue\MissingConstructorCall($classDefinition); } } foreach ($classDefinition->methods() as $methodDefinition) { switch ($methodDefinition->name()) { case '__construct': case '__wakeup': break; case '__destruct': case '__toString': if ($this->methodHasCall($methodDefinition, $propertyName) || $this->methodHasStaticCall($methodDefinition, $expectedfacadeClassName)) { $issues[] = new Issue\MethodIssue\InadmissibleMethodCall($classDefinition, $methodDefinition); } break; case 'unserialize': if ($this->classImplementsSerializable($classDefinition)) { break; } default: if ($methodDefinition->isAbstract()) { break; } $missingCall = false; if ($methodDefinition->isStatic()) { $missingCall = !$this->methodHasStaticCall($methodDefinition, $expectedfacadeClassName); } else { if ($this->methodHasCall($methodDefinition, $propertyName)) { $hasNonStaticCalls = true; } elseif (!$this->methodHasStaticCall($methodDefinition, $expectedfacadeClassName)) { $missingCall = true; } } if ($missingCall) { $issues[] = new Issue\MethodIssue\MissingMethodCall($classDefinition, $methodDefinition); } } if (!$methodDefinition->isAbstract()) { $methodReflector = $methodDefinition->createReflector(); $blockComment = $methodReflector->getDocComment(); if (false === $blockComment) { $documentedParameterList = new ParameterList(); } else { $documentedParameterList = $this->parameterListParser()->parseBlockComment($classDefinition->className(), $methodDefinition->name(), $blockComment); } $documentedParameterList = $documentedParameterList->accept($this->createClassNameResolver($classDefinition)); $this->mergeTool()->clearIssues(); $this->mergeTool()->merge($configuration, $classDefinition, $methodDefinition, $documentedParameterList, $this->parameterListParser()->parseReflector($methodReflector)); $issues = array_merge($issues, $this->mergeTool()->issues()); } } if ($hasNonStaticCalls && !$hasConstructorInit) { array_unshift($issues, new Issue\ClassIssue\MissingConstructorCall($classDefinition)); } if ($hasConstructorInit) { if ($classDefinition->hasProperty($propertyName)) { $typhoonProperty = $classDefinition->property($propertyName); $missingProperty = $typhoonProperty->isStatic() || AccessModifier::PRIVATE_() !== $typhoonProperty->accessModifier(); } else { $missingProperty = true; } if ($missingProperty) { $issues[] = new Issue\ClassIssue\MissingProperty($classDefinition); } } }
/** * @return ConcreteMethod */ protected function generateCallMethod() { $this->typeCheck->generateCallMethod(func_get_args()); $nameIdentifier = new Identifier('name'); $nameVariable = new Variable($nameIdentifier); $argumentsIdentifier = new Identifier('arguments'); $validatorMethodNameVariable = new Variable(new Identifier('validatorMethodName')); $thisVariable = new Variable(new Identifier('this')); $reflectorMember = new Member($thisVariable, new Constant(new Identifier('reflector'))); $method = new ConcreteMethod(new Identifier('__call'), AccessModifier::PUBLIC_()); $method->addParameter(new Parameter($nameIdentifier)); $method->addParameter(new Parameter($argumentsIdentifier, new ArrayTypeHint())); $ltrimCall = new Call(QualifiedIdentifier::fromString('\\ltrim')); $ltrimCall->add($nameVariable); $ltrimCall->add(new Literal('_')); $ucfirstCall = new Call(QualifiedIdentifier::fromString('\\ucfirst')); $ucfirstCall->add($ltrimCall); $validatorMethodNameSprintfCall = new Call(QualifiedIdentifier::fromString('\\sprintf')); $validatorMethodNameSprintfCall->add(new Literal('validate%s')); $validatorMethodNameSprintfCall->add($ucfirstCall); $method->statementBlock()->add(new ExpressionStatement(new Assign($validatorMethodNameVariable, $validatorMethodNameSprintfCall))); $reflectorHasMethodCall = new Call(new Member($reflectorMember, new Constant(new Identifier('hasMethod')))); $reflectorHasMethodCall->add($validatorMethodNameVariable); $undefinedMethodIf = new IfStatement(new LogicalNot($reflectorHasMethodCall)); $exceptionMessageSprintfCall = new Call(QualifiedIdentifier::fromString('\\sprintf')); $exceptionMessageSprintfCall->add(new Literal('Call to undefined method %s::%s().')); $exceptionMessageSprintfCall->add(new Constant(new Identifier('__CLASS__'))); $exceptionMessageSprintfCall->add($nameVariable); $newBadMethodCallExceptionCall = new Call(QualifiedIdentifier::fromString('\\BadMethodCallException')); $newBadMethodCallExceptionCall->add($exceptionMessageSprintfCall); $undefinedMethodIf->trueBranch()->add(new ThrowStatement(new NewOperator($newBadMethodCallExceptionCall))); $method->statementBlock()->add($undefinedMethodIf); $getMethodCall = new Call(new Member($reflectorMember, new Constant(new Identifier('getMethod')))); $getMethodCall->add($validatorMethodNameVariable); $invokeArgsCall = new Call(new Member($getMethodCall, new Constant(new Identifier('invokeArgs')))); $invokeArgsCall->add($thisVariable); $invokeArgsCall->add(new Variable($argumentsIdentifier)); $method->statementBlock()->add(new ReturnStatement($invokeArgsCall)); return $method; }
/** * @param RuntimeConfiguration $configuration * * @return ConcreteMethod */ protected function generateConfigurationMethod(RuntimeConfiguration $configuration) { $this->typeCheck->generateConfigurationMethod(func_get_args()); $method = new ConcreteMethod(new Identifier('configuration'), AccessModifier::PROTECTED_(), true); $method->statementBlock()->add(new ReturnStatement($this->configurationGenerator()->generate($configuration))); return $method; }
/** * @param tuple<integer,string,integer> $token * @param array<string|array> &$tokens * @param null &$accessModifier * @param null &$isStatic * @param null &$isAbstract * @param null &$source * * @return tuple<integer|string,string,integer|null> */ protected function parseClassMemberModifiers(array $token, array &$tokens, &$accessModifier, &$isStatic, &$isAbstract, &$source) { $this->typeCheck->parseClassMemberModifiers(func_get_args()); $isStatic = false; $isAbstract = false; $source = ''; while ($token) { $token = $this->normalizeToken($token); $source .= $token[1]; if (T_FUNCTION === $token[0] || T_VARIABLE === $token[0]) { break; } elseif (T_PUBLIC === $token[0] || T_PROTECTED === $token[0] || T_PRIVATE === $token[0]) { $accessModifier = AccessModifier::instanceByValue(strtolower($token[1])); } elseif (T_STATIC === $token[0]) { $isStatic = true; } elseif (T_ABSTRACT === $token[0]) { $isAbstract = true; } $token = next($tokens); } return $token; }
/** * @return ConcreteMethod */ protected function generateConstructor() { $this->typeCheck->generateConstructor(func_get_args()); $messageIdentifier = new Identifier('message'); $previousIdentifier = new Identifier('previous'); $method = new ConcreteMethod(new Identifier('__construct'), AccessModifier::PUBLIC_()); $method->addParameter(new Parameter($messageIdentifier)); $previousParameter = new Parameter($previousIdentifier, new ObjectTypeHint(QualifiedIdentifier::fromString('\\Exception'))); $previousParameter->setDefaultValue(new Literal(null)); $method->addParameter($previousParameter); $parentConstructCall = new Call(new StaticMember(new Constant(new Identifier('parent')), new Constant(new Identifier('__construct')))); $parentConstructCall->add(new Variable($messageIdentifier)); $parentConstructCall->add(new Literal(0)); $parentConstructCall->add(new Variable($previousIdentifier)); $method->statementBlock()->add(new ExpressionStatement($parentConstructCall)); return $method; }