/** * @param \PHPSemVerChecker\Registry\Registry $registryBefore * @param \PHPSemVerChecker\Registry\Registry $registryAfter * @return \PHPSemVerChecker\Report\Report */ public function analyze(Registry $registryBefore, Registry $registryAfter) { $report = new Report(); $keysBefore = array_keys($registryBefore->data['function']); $keysAfter = array_keys($registryAfter->data['function']); $added = array_diff($keysAfter, $keysBefore); $removed = array_diff($keysBefore, $keysAfter); $toVerify = array_intersect($keysBefore, $keysAfter); foreach ($removed as $key) { $fileBefore = $registryBefore->mapping['function'][$key]; $functionBefore = $registryBefore->data['function'][$key]; $data = new FunctionRemoved($fileBefore, $functionBefore); $report->addFunction($data); } foreach ($toVerify as $key) { $fileBefore = $registryBefore->mapping['function'][$key]; $functionBefore = $registryBefore->data['function'][$key]; $fileAfter = $registryAfter->mapping['function'][$key]; $functionAfter = $registryAfter->data['function'][$key]; // Leave non-strict comparison here if ($functionBefore != $functionAfter) { $paramsBefore = $functionBefore->params; $paramsAfter = $functionAfter->params; $signatureResult = Signature::analyze($paramsBefore, $paramsAfter); $changes = ['parameter_added' => FunctionParameterAdded::class, 'parameter_removed' => FunctionParameterRemoved::class, 'parameter_renamed' => FunctionParameterNameChanged::class, 'parameter_typing_added' => FunctionParameterTypingAdded::class, 'parameter_typing_removed' => FunctionParameterTypingRemoved::class, 'parameter_default_added' => FunctionParameterDefaultAdded::class, 'parameter_default_removed' => FunctionParameterDefaultRemoved::class, 'parameter_default_value_changed' => FunctionParameterDefaultValueChanged::class]; foreach ($changes as $changeType => $class) { if (!$signatureResult[$changeType]) { continue; } if (is_a($class, FunctionOperationUnary::class, true)) { $data = new $class($fileAfter, $functionAfter); } else { $data = new $class($fileBefore, $functionBefore, $fileAfter, $functionAfter); } $report->addFunction($data); } // Difference in source code if (!Implementation::isSame($functionBefore->stmts, $functionAfter->stmts)) { $data = new FunctionImplementationChanged($fileBefore, $functionBefore, $fileAfter, $functionAfter); $report->addFunction($data); } } } foreach ($added as $key) { $fileAfter = $registryAfter->mapping['function'][$key]; $functionAfter = $registryAfter->data['function'][$key]; $data = new FunctionAdded($fileAfter, $functionAfter); $report->addFunction($data); } return $report; }
/** * @param \PHPSemVerChecker\Registry\Registry $registryBefore * @param \PHPSemVerChecker\Registry\Registry $registryAfter * @return \PHPSemVerChecker\Report\Report */ public function analyze(Registry $registryBefore, Registry $registryAfter) { $report = new Report(); $keysBefore = array_keys($registryBefore->data['function']); $keysAfter = array_keys($registryAfter->data['function']); $added = array_diff($keysAfter, $keysBefore); $removed = array_diff($keysBefore, $keysAfter); $toVerify = array_intersect($keysBefore, $keysAfter); foreach ($removed as $key) { $fileBefore = $registryBefore->mapping['function'][$key]; $functionBefore = $registryBefore->data['function'][$key]; $data = new FunctionRemoved($fileBefore, $functionBefore); $report->addFunction($data); } foreach ($toVerify as $key) { $fileBefore = $registryBefore->mapping['function'][$key]; $functionBefore = $registryBefore->data['function'][$key]; $fileAfter = $registryAfter->mapping['function'][$key]; $functionAfter = $registryAfter->data['function'][$key]; // Leave non-strict comparison here if ($functionBefore != $functionAfter) { $paramsBefore = $functionBefore->params; $paramsAfter = $functionAfter->params; // Signature if (!Signature::isSameTypehints($paramsBefore, $paramsAfter)) { $data = new FunctionParameterChanged($fileBefore, $functionBefore, $fileAfter, $functionAfter); $report->addFunction($data); continue; } if (!Signature::isSameVariables($paramsBefore, $paramsAfter)) { $data = new FunctionParameterNameChanged($fileBefore, $functionBefore, $fileAfter, $functionAfter); $report->addFunction($data); continue; } // Different length (considering params with defaults) // Difference in source code if ($functionBefore->stmts != $functionAfter->stmts) { $data = new FunctionImplementationChanged($fileBefore, $functionBefore, $fileAfter, $functionAfter); $report->addFunction($data); continue; } } } foreach ($added as $key) { $fileAfter = $registryAfter->mapping['function'][$key]; $functionAfter = $registryAfter->data['function'][$key]; $data = new FunctionAdded($fileAfter, $functionAfter); $report->addFunction($data); } return $report; }
public function analyze(Stmt $contextBefore, Stmt $contextAfter) { $report = new Report(); $methodsBefore = $contextBefore->getMethods(); $methodsAfter = $contextAfter->getMethods(); $methodsBeforeKeyed = []; foreach ($methodsBefore as $method) { $methodsBeforeKeyed[$method->name] = $method; } $methodsAfterKeyed = []; foreach ($methodsAfter as $method) { $methodsAfterKeyed[$method->name] = $method; } $methodNamesBefore = array_keys($methodsBeforeKeyed); $methodNamesAfter = array_keys($methodsAfterKeyed); $methodsAdded = array_diff($methodNamesAfter, $methodNamesBefore); $methodsRemoved = array_diff($methodNamesBefore, $methodNamesAfter); $methodsToVerify = array_intersect($methodNamesBefore, $methodNamesAfter); // Here we only care about public methods as they are the only part of the API we care about // Removed methods can either be implemented in parent classes or not exist anymore foreach ($methodsRemoved as $method) { $methodBefore = $methodsBeforeKeyed[$method]; $data = new ClassMethodRemoved($this->context, $this->fileBefore, $contextBefore, $methodBefore); $report->add($this->context, $data); } foreach ($methodsToVerify as $method) { /** @var \PhpParser\Node\Stmt\ClassMethod $methodBefore */ $methodBefore = $methodsBeforeKeyed[$method]; /** @var \PhpParser\Node\Stmt\ClassMethod $methodAfter */ $methodAfter = $methodsAfterKeyed[$method]; // Leave non-strict comparison here if ($methodBefore != $methodAfter) { $paramsBefore = $methodBefore->params; $paramsAfter = $methodAfter->params; // Signature $signatureChanged = false; if (!Signature::isSameTypehints($paramsBefore, $paramsAfter)) { $data = new ClassMethodParameterChanged($this->context, $this->fileBefore, $contextBefore, $methodBefore, $this->fileAfter, $contextAfter, $methodAfter); $report->add($this->context, $data); $signatureChanged = true; } if (!$signatureChanged && !Signature::isSameVariables($paramsBefore, $paramsAfter)) { $data = new ClassMethodParameterNameChanged($this->context, $this->fileBefore, $contextBefore, $methodBefore, $this->fileAfter, $contextAfter, $methodAfter); $report->add($this->context, $data); } // Different length (considering params with defaults) // Difference in source code if ($methodBefore->stmts != $methodAfter->stmts) { $data = new ClassMethodImplementationChanged($this->context, $this->fileBefore, $contextBefore, $methodBefore, $this->fileAfter, $contextAfter, $methodAfter); $report->add($this->context, $data); } } } // Added methods implies MINOR BUMP foreach ($methodsAdded as $method) { $methodAfter = $methodsAfterKeyed[$method]; $data = new ClassMethodAdded($this->context, $this->fileAfter, $contextAfter, $methodAfter); $report->add($this->context, $data); } return $report; }
public function analyze(Stmt $contextBefore, Stmt $contextAfter) { $report = new Report(); $methodsBefore = $contextBefore->getMethods(); $methodsAfter = $contextAfter->getMethods(); $methodsBeforeKeyed = []; foreach ($methodsBefore as $method) { $methodsBeforeKeyed[$method->name] = $method; } $methodsAfterKeyed = []; foreach ($methodsAfter as $method) { $methodsAfterKeyed[$method->name] = $method; } $methodNamesBefore = array_keys($methodsBeforeKeyed); $methodNamesAfter = array_keys($methodsAfterKeyed); $methodsAdded = array_diff($methodNamesAfter, $methodNamesBefore); $methodsRemoved = array_diff($methodNamesBefore, $methodNamesAfter); $methodsToVerify = array_intersect($methodNamesBefore, $methodNamesAfter); // Here we only care about public methods as they are the only part of the API we care about // Removed methods can either be implemented in parent classes or not exist anymore foreach ($methodsRemoved as $method) { $methodBefore = $methodsBeforeKeyed[$method]; $data = new ClassMethodRemoved($this->context, $this->fileBefore, $contextBefore, $methodBefore); $report->add($this->context, $data); } foreach ($methodsToVerify as $method) { /** @var \PhpParser\Node\Stmt\ClassMethod $methodBefore */ $methodBefore = $methodsBeforeKeyed[$method]; /** @var \PhpParser\Node\Stmt\ClassMethod $methodAfter */ $methodAfter = $methodsAfterKeyed[$method]; // Leave non-strict comparison here if ($methodBefore != $methodAfter) { $paramsBefore = $methodBefore->params; $paramsAfter = $methodAfter->params; $signatureResult = Signature::analyze($paramsBefore, $paramsAfter); $changes = ['parameter_added' => ClassMethodParameterAdded::class, 'parameter_removed' => ClassMethodParameterRemoved::class, 'parameter_renamed' => ClassMethodParameterNameChanged::class, 'parameter_typing_added' => ClassMethodParameterTypingAdded::class, 'parameter_typing_removed' => ClassMethodParameterTypingRemoved::class, 'parameter_default_added' => ClassMethodParameterDefaultAdded::class, 'parameter_default_removed' => ClassMethodParameterDefaultRemoved::class, 'parameter_default_value_changed' => ClassMethodParameterDefaultValueChanged::class]; foreach ($changes as $changeType => $class) { if (!$signatureResult[$changeType]) { continue; } if (is_a($class, ClassMethodOperationUnary::class, true)) { $data = new $class($this->context, $this->fileAfter, $contextAfter, $methodAfter); } else { $data = new $class($this->context, $this->fileBefore, $contextBefore, $methodBefore, $this->fileAfter, $contextAfter, $methodAfter); } $report->add($this->context, $data); } // Difference in source code // Cast to array because interfaces do not have stmts (= null) if (!Implementation::isSame((array) $methodBefore->stmts, (array) $methodAfter->stmts)) { $data = new ClassMethodImplementationChanged($this->context, $this->fileBefore, $contextBefore, $methodBefore, $this->fileAfter, $contextAfter, $methodAfter); $report->add($this->context, $data); } } } // Added methods implies MINOR BUMP foreach ($methodsAdded as $method) { $methodAfter = $methodsAfterKeyed[$method]; $data = new ClassMethodAdded($this->context, $this->fileAfter, $contextAfter, $methodAfter); $report->add($this->context, $data); } return $report; }