propertyFetchAnalyzer = $propertyFetchAnalyzer; $this->magicPropertyFetchAnalyzer = $magicPropertyFetchAnalyzer; } public function getRuleDefinition() : RuleDefinition { return new RuleDefinition('Turns defined `__get`/`__set` to specific method calls.', [new ConfiguredCodeSample(<<<'CODE_SAMPLE' $container = new SomeContainer; $container->someService = $someService; CODE_SAMPLE , <<<'CODE_SAMPLE' $container = new SomeContainer; $container->setService("someService", $someService); CODE_SAMPLE , [new GetAndSetToMethodCall('SomeContainer', 'addService', 'getService')])]); } /** * @return array> */ public function getNodeTypes() : array { return [Assign::class, PropertyFetch::class]; } /** * @param Assign|PropertyFetch $node */ public function refactorWithScope(Node $node, Scope $scope) : ?Node { if ($node instanceof Assign) { if ($node->var instanceof PropertyFetch) { return $this->processMagicSet($node->expr, $node->var, $scope); } return null; } return $this->processPropertyFetch($node, $scope); } /** * @param mixed[] $configuration */ public function configure(array $configuration) : void { Assert::allIsAOf($configuration, GetAndSetToMethodCall::class); $this->getAndSetToMethodCalls = $configuration; } private function processMagicSet(Expr $expr, PropertyFetch $propertyFetch, Scope $scope) : ?Node { foreach ($this->getAndSetToMethodCalls as $getAndSetToMethodCall) { $objectType = $getAndSetToMethodCall->getObjectType(); if ($this->shouldSkipPropertyFetch($propertyFetch, $objectType, $scope)) { continue; } return $this->createMethodCallNodeFromAssignNode($propertyFetch, $expr, $getAndSetToMethodCall->getSetMethod()); } return null; } private function processPropertyFetch(PropertyFetch $propertyFetch, Scope $scope) : ?MethodCall { $parentNode = $propertyFetch->getAttribute(AttributeKey::PARENT_NODE); foreach ($this->getAndSetToMethodCalls as $getAndSetToMethodCall) { if ($this->shouldSkipPropertyFetch($propertyFetch, $getAndSetToMethodCall->getObjectType(), $scope)) { continue; } // setter, skip if (!$parentNode instanceof Assign) { return $this->createMethodCallNodeFromPropertyFetchNode($propertyFetch, $getAndSetToMethodCall->getGetMethod()); } if ($parentNode->var !== $propertyFetch) { return $this->createMethodCallNodeFromPropertyFetchNode($propertyFetch, $getAndSetToMethodCall->getGetMethod()); } } return null; } private function shouldSkipPropertyFetch(PropertyFetch $propertyFetch, ObjectType $objectType, Scope $scope) : bool { if (!$this->isObjectType($propertyFetch->var, $objectType)) { return \true; } if (!$this->magicPropertyFetchAnalyzer->isMagicOnType($propertyFetch, $objectType, $scope)) { return \true; } return $this->propertyFetchAnalyzer->isPropertyToSelf($propertyFetch); } private function createMethodCallNodeFromAssignNode(PropertyFetch $propertyFetch, Expr $expr, string $method) : MethodCall { $propertyName = $this->getName($propertyFetch->name); return $this->nodeFactory->createMethodCall($propertyFetch->var, $method, [$propertyName, $expr]); } private function createMethodCallNodeFromPropertyFetchNode(PropertyFetch $propertyFetch, string $method) : MethodCall { /** @var Variable $variableNode */ $variableNode = $propertyFetch->var; return $this->nodeFactory->createMethodCall($variableNode, $method, [$this->getName($propertyFetch)]); } }