Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@14: declare(strict_types=1); Chris@14: Chris@0: namespace SebastianBergmann\GlobalState; Chris@0: Chris@0: use ReflectionProperty; Chris@0: Chris@0: /** Chris@0: * Restorer of snapshots of global state. Chris@0: */ Chris@0: class Restorer Chris@0: { Chris@0: /** Chris@0: * Deletes function definitions that are not defined in a snapshot. Chris@0: * Chris@0: * @throws RuntimeException when the uopz_delete() function is not available Chris@14: * Chris@0: * @see https://github.com/krakjoe/uopz Chris@0: */ Chris@0: public function restoreFunctions(Snapshot $snapshot) Chris@0: { Chris@14: if (!\function_exists('uopz_delete')) { Chris@0: throw new RuntimeException('The uopz_delete() function is required for this operation'); Chris@0: } Chris@0: Chris@14: $functions = \get_defined_functions(); Chris@0: Chris@14: foreach (\array_diff($functions['user'], $snapshot->functions()) as $function) { Chris@0: uopz_delete($function); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Restores all global and super-global variables from a snapshot. Chris@0: */ Chris@0: public function restoreGlobalVariables(Snapshot $snapshot) Chris@0: { Chris@0: $superGlobalArrays = $snapshot->superGlobalArrays(); Chris@0: Chris@0: foreach ($superGlobalArrays as $superGlobalArray) { Chris@0: $this->restoreSuperGlobalArray($snapshot, $superGlobalArray); Chris@0: } Chris@0: Chris@0: $globalVariables = $snapshot->globalVariables(); Chris@0: Chris@14: foreach (\array_keys($GLOBALS) as $key) { Chris@0: if ($key != 'GLOBALS' && Chris@14: !\in_array($key, $superGlobalArrays) && Chris@0: !$snapshot->blacklist()->isGlobalVariableBlacklisted($key)) { Chris@14: if (\array_key_exists($key, $globalVariables)) { Chris@0: $GLOBALS[$key] = $globalVariables[$key]; Chris@0: } else { Chris@0: unset($GLOBALS[$key]); Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Restores all static attributes in user-defined classes from this snapshot. Chris@0: */ Chris@0: public function restoreStaticAttributes(Snapshot $snapshot) Chris@0: { Chris@0: $current = new Snapshot($snapshot->blacklist(), false, false, false, false, true, false, false, false, false); Chris@14: $newClasses = \array_diff($current->classes(), $snapshot->classes()); Chris@14: Chris@0: unset($current); Chris@0: Chris@0: foreach ($snapshot->staticAttributes() as $className => $staticAttributes) { Chris@0: foreach ($staticAttributes as $name => $value) { Chris@0: $reflector = new ReflectionProperty($className, $name); Chris@0: $reflector->setAccessible(true); Chris@0: $reflector->setValue($value); Chris@0: } Chris@0: } Chris@0: Chris@0: foreach ($newClasses as $className) { Chris@0: $class = new \ReflectionClass($className); Chris@0: $defaults = $class->getDefaultProperties(); Chris@0: Chris@0: foreach ($class->getProperties() as $attribute) { Chris@0: if (!$attribute->isStatic()) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $name = $attribute->getName(); Chris@0: Chris@0: if ($snapshot->blacklist()->isStaticAttributeBlacklisted($className, $name)) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: if (!isset($defaults[$name])) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $attribute->setAccessible(true); Chris@0: $attribute->setValue($defaults[$name]); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Restores a super-global variable array from this snapshot. Chris@0: */ Chris@14: private function restoreSuperGlobalArray(Snapshot $snapshot, string $superGlobalArray) Chris@0: { Chris@0: $superGlobalVariables = $snapshot->superGlobalVariables(); Chris@0: Chris@0: if (isset($GLOBALS[$superGlobalArray]) && Chris@14: \is_array($GLOBALS[$superGlobalArray]) && Chris@0: isset($superGlobalVariables[$superGlobalArray])) { Chris@14: $keys = \array_keys( Chris@14: \array_merge( Chris@0: $GLOBALS[$superGlobalArray], Chris@0: $superGlobalVariables[$superGlobalArray] Chris@0: ) Chris@0: ); Chris@0: Chris@0: foreach ($keys as $key) { Chris@0: if (isset($superGlobalVariables[$superGlobalArray][$key])) { Chris@0: $GLOBALS[$superGlobalArray][$key] = $superGlobalVariables[$superGlobalArray][$key]; Chris@0: } else { Chris@0: unset($GLOBALS[$superGlobalArray][$key]); Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: }