annotate vendor/sebastian/global-state/src/Snapshot.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 1fec387a4317
children
rev   line source
Chris@0 1 <?php
Chris@0 2 /*
Chris@14 3 * This file is part of sebastian/global-state.
Chris@0 4 *
Chris@0 5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
Chris@0 6 *
Chris@0 7 * For the full copyright and license information, please view the LICENSE
Chris@0 8 * file that was distributed with this source code.
Chris@0 9 */
Chris@0 10
Chris@14 11 declare(strict_types=1);
Chris@14 12
Chris@0 13 namespace SebastianBergmann\GlobalState;
Chris@0 14
Chris@0 15 use ReflectionClass;
Chris@0 16 use Serializable;
Chris@0 17
Chris@0 18 /**
Chris@0 19 * A snapshot of global state.
Chris@0 20 */
Chris@0 21 class Snapshot
Chris@0 22 {
Chris@0 23 /**
Chris@0 24 * @var Blacklist
Chris@0 25 */
Chris@0 26 private $blacklist;
Chris@0 27
Chris@0 28 /**
Chris@0 29 * @var array
Chris@0 30 */
Chris@14 31 private $globalVariables = [];
Chris@0 32
Chris@0 33 /**
Chris@0 34 * @var array
Chris@0 35 */
Chris@14 36 private $superGlobalArrays = [];
Chris@0 37
Chris@0 38 /**
Chris@0 39 * @var array
Chris@0 40 */
Chris@14 41 private $superGlobalVariables = [];
Chris@0 42
Chris@0 43 /**
Chris@0 44 * @var array
Chris@0 45 */
Chris@14 46 private $staticAttributes = [];
Chris@0 47
Chris@0 48 /**
Chris@0 49 * @var array
Chris@0 50 */
Chris@14 51 private $iniSettings = [];
Chris@0 52
Chris@0 53 /**
Chris@0 54 * @var array
Chris@0 55 */
Chris@14 56 private $includedFiles = [];
Chris@0 57
Chris@0 58 /**
Chris@0 59 * @var array
Chris@0 60 */
Chris@14 61 private $constants = [];
Chris@0 62
Chris@0 63 /**
Chris@0 64 * @var array
Chris@0 65 */
Chris@14 66 private $functions = [];
Chris@0 67
Chris@0 68 /**
Chris@0 69 * @var array
Chris@0 70 */
Chris@14 71 private $interfaces = [];
Chris@0 72
Chris@0 73 /**
Chris@0 74 * @var array
Chris@0 75 */
Chris@14 76 private $classes = [];
Chris@0 77
Chris@0 78 /**
Chris@0 79 * @var array
Chris@0 80 */
Chris@14 81 private $traits = [];
Chris@0 82
Chris@0 83 /**
Chris@0 84 * Creates a snapshot of the current global state.
Chris@0 85 */
Chris@14 86 public function __construct(Blacklist $blacklist = null, bool $includeGlobalVariables = true, bool $includeStaticAttributes = true, bool $includeConstants = true, bool $includeFunctions = true, bool $includeClasses = true, bool $includeInterfaces = true, bool $includeTraits = true, bool $includeIniSettings = true, bool $includeIncludedFiles = true)
Chris@0 87 {
Chris@0 88 if ($blacklist === null) {
Chris@0 89 $blacklist = new Blacklist;
Chris@0 90 }
Chris@0 91
Chris@0 92 $this->blacklist = $blacklist;
Chris@0 93
Chris@0 94 if ($includeConstants) {
Chris@0 95 $this->snapshotConstants();
Chris@0 96 }
Chris@0 97
Chris@0 98 if ($includeFunctions) {
Chris@0 99 $this->snapshotFunctions();
Chris@0 100 }
Chris@0 101
Chris@0 102 if ($includeClasses || $includeStaticAttributes) {
Chris@0 103 $this->snapshotClasses();
Chris@0 104 }
Chris@0 105
Chris@0 106 if ($includeInterfaces) {
Chris@0 107 $this->snapshotInterfaces();
Chris@0 108 }
Chris@0 109
Chris@0 110 if ($includeGlobalVariables) {
Chris@0 111 $this->setupSuperGlobalArrays();
Chris@0 112 $this->snapshotGlobals();
Chris@0 113 }
Chris@0 114
Chris@0 115 if ($includeStaticAttributes) {
Chris@0 116 $this->snapshotStaticAttributes();
Chris@0 117 }
Chris@0 118
Chris@0 119 if ($includeIniSettings) {
Chris@14 120 $this->iniSettings = \ini_get_all(null, false);
Chris@0 121 }
Chris@0 122
Chris@0 123 if ($includeIncludedFiles) {
Chris@14 124 $this->includedFiles = \get_included_files();
Chris@0 125 }
Chris@0 126
Chris@14 127 $this->traits = \get_declared_traits();
Chris@0 128 }
Chris@0 129
Chris@14 130 public function blacklist(): Blacklist
Chris@0 131 {
Chris@0 132 return $this->blacklist;
Chris@0 133 }
Chris@0 134
Chris@14 135 public function globalVariables(): array
Chris@0 136 {
Chris@0 137 return $this->globalVariables;
Chris@0 138 }
Chris@0 139
Chris@14 140 public function superGlobalVariables(): array
Chris@0 141 {
Chris@0 142 return $this->superGlobalVariables;
Chris@0 143 }
Chris@0 144
Chris@14 145 public function superGlobalArrays(): array
Chris@0 146 {
Chris@0 147 return $this->superGlobalArrays;
Chris@0 148 }
Chris@0 149
Chris@14 150 public function staticAttributes(): array
Chris@0 151 {
Chris@0 152 return $this->staticAttributes;
Chris@0 153 }
Chris@0 154
Chris@14 155 public function iniSettings(): array
Chris@0 156 {
Chris@0 157 return $this->iniSettings;
Chris@0 158 }
Chris@0 159
Chris@14 160 public function includedFiles(): array
Chris@0 161 {
Chris@0 162 return $this->includedFiles;
Chris@0 163 }
Chris@0 164
Chris@14 165 public function constants(): array
Chris@0 166 {
Chris@0 167 return $this->constants;
Chris@0 168 }
Chris@0 169
Chris@14 170 public function functions(): array
Chris@0 171 {
Chris@0 172 return $this->functions;
Chris@0 173 }
Chris@0 174
Chris@14 175 public function interfaces(): array
Chris@0 176 {
Chris@0 177 return $this->interfaces;
Chris@0 178 }
Chris@0 179
Chris@14 180 public function classes(): array
Chris@0 181 {
Chris@0 182 return $this->classes;
Chris@0 183 }
Chris@0 184
Chris@14 185 public function traits(): array
Chris@0 186 {
Chris@0 187 return $this->traits;
Chris@0 188 }
Chris@0 189
Chris@0 190 /**
Chris@0 191 * Creates a snapshot user-defined constants.
Chris@0 192 */
Chris@0 193 private function snapshotConstants()
Chris@0 194 {
Chris@14 195 $constants = \get_defined_constants(true);
Chris@0 196
Chris@0 197 if (isset($constants['user'])) {
Chris@0 198 $this->constants = $constants['user'];
Chris@0 199 }
Chris@0 200 }
Chris@0 201
Chris@0 202 /**
Chris@0 203 * Creates a snapshot user-defined functions.
Chris@0 204 */
Chris@0 205 private function snapshotFunctions()
Chris@0 206 {
Chris@14 207 $functions = \get_defined_functions();
Chris@0 208
Chris@0 209 $this->functions = $functions['user'];
Chris@0 210 }
Chris@0 211
Chris@0 212 /**
Chris@0 213 * Creates a snapshot user-defined classes.
Chris@0 214 */
Chris@0 215 private function snapshotClasses()
Chris@0 216 {
Chris@14 217 foreach (\array_reverse(\get_declared_classes()) as $className) {
Chris@0 218 $class = new ReflectionClass($className);
Chris@0 219
Chris@0 220 if (!$class->isUserDefined()) {
Chris@0 221 break;
Chris@0 222 }
Chris@0 223
Chris@0 224 $this->classes[] = $className;
Chris@0 225 }
Chris@0 226
Chris@14 227 $this->classes = \array_reverse($this->classes);
Chris@0 228 }
Chris@0 229
Chris@0 230 /**
Chris@0 231 * Creates a snapshot user-defined interfaces.
Chris@0 232 */
Chris@0 233 private function snapshotInterfaces()
Chris@0 234 {
Chris@14 235 foreach (\array_reverse(\get_declared_interfaces()) as $interfaceName) {
Chris@0 236 $class = new ReflectionClass($interfaceName);
Chris@0 237
Chris@0 238 if (!$class->isUserDefined()) {
Chris@0 239 break;
Chris@0 240 }
Chris@0 241
Chris@0 242 $this->interfaces[] = $interfaceName;
Chris@0 243 }
Chris@0 244
Chris@14 245 $this->interfaces = \array_reverse($this->interfaces);
Chris@0 246 }
Chris@0 247
Chris@0 248 /**
Chris@0 249 * Creates a snapshot of all global and super-global variables.
Chris@0 250 */
Chris@0 251 private function snapshotGlobals()
Chris@0 252 {
Chris@0 253 $superGlobalArrays = $this->superGlobalArrays();
Chris@0 254
Chris@0 255 foreach ($superGlobalArrays as $superGlobalArray) {
Chris@0 256 $this->snapshotSuperGlobalArray($superGlobalArray);
Chris@0 257 }
Chris@0 258
Chris@14 259 foreach (\array_keys($GLOBALS) as $key) {
Chris@0 260 if ($key != 'GLOBALS' &&
Chris@14 261 !\in_array($key, $superGlobalArrays) &&
Chris@0 262 $this->canBeSerialized($GLOBALS[$key]) &&
Chris@0 263 !$this->blacklist->isGlobalVariableBlacklisted($key)) {
Chris@14 264 $this->globalVariables[$key] = \unserialize(\serialize($GLOBALS[$key]));
Chris@0 265 }
Chris@0 266 }
Chris@0 267 }
Chris@0 268
Chris@0 269 /**
Chris@0 270 * Creates a snapshot a super-global variable array.
Chris@0 271 */
Chris@14 272 private function snapshotSuperGlobalArray(string $superGlobalArray)
Chris@0 273 {
Chris@14 274 $this->superGlobalVariables[$superGlobalArray] = [];
Chris@0 275
Chris@14 276 if (isset($GLOBALS[$superGlobalArray]) && \is_array($GLOBALS[$superGlobalArray])) {
Chris@0 277 foreach ($GLOBALS[$superGlobalArray] as $key => $value) {
Chris@14 278 $this->superGlobalVariables[$superGlobalArray][$key] = \unserialize(\serialize($value));
Chris@0 279 }
Chris@0 280 }
Chris@0 281 }
Chris@0 282
Chris@0 283 /**
Chris@0 284 * Creates a snapshot of all static attributes in user-defined classes.
Chris@0 285 */
Chris@0 286 private function snapshotStaticAttributes()
Chris@0 287 {
Chris@0 288 foreach ($this->classes as $className) {
Chris@0 289 $class = new ReflectionClass($className);
Chris@14 290 $snapshot = [];
Chris@0 291
Chris@0 292 foreach ($class->getProperties() as $attribute) {
Chris@0 293 if ($attribute->isStatic()) {
Chris@0 294 $name = $attribute->getName();
Chris@0 295
Chris@0 296 if ($this->blacklist->isStaticAttributeBlacklisted($className, $name)) {
Chris@0 297 continue;
Chris@0 298 }
Chris@0 299
Chris@0 300 $attribute->setAccessible(true);
Chris@0 301 $value = $attribute->getValue();
Chris@0 302
Chris@0 303 if ($this->canBeSerialized($value)) {
Chris@14 304 $snapshot[$name] = \unserialize(\serialize($value));
Chris@0 305 }
Chris@0 306 }
Chris@0 307 }
Chris@0 308
Chris@0 309 if (!empty($snapshot)) {
Chris@0 310 $this->staticAttributes[$className] = $snapshot;
Chris@0 311 }
Chris@0 312 }
Chris@0 313 }
Chris@0 314
Chris@0 315 /**
Chris@0 316 * Returns a list of all super-global variable arrays.
Chris@0 317 */
Chris@0 318 private function setupSuperGlobalArrays()
Chris@0 319 {
Chris@14 320 $this->superGlobalArrays = [
Chris@0 321 '_ENV',
Chris@0 322 '_POST',
Chris@0 323 '_GET',
Chris@0 324 '_COOKIE',
Chris@0 325 '_SERVER',
Chris@0 326 '_FILES',
Chris@0 327 '_REQUEST'
Chris@14 328 ];
Chris@0 329
Chris@14 330 if (\ini_get('register_long_arrays') == '1') {
Chris@14 331 $this->superGlobalArrays = \array_merge(
Chris@0 332 $this->superGlobalArrays,
Chris@14 333 [
Chris@0 334 'HTTP_ENV_VARS',
Chris@0 335 'HTTP_POST_VARS',
Chris@0 336 'HTTP_GET_VARS',
Chris@0 337 'HTTP_COOKIE_VARS',
Chris@0 338 'HTTP_SERVER_VARS',
Chris@0 339 'HTTP_POST_FILES'
Chris@14 340 ]
Chris@0 341 );
Chris@0 342 }
Chris@0 343 }
Chris@0 344
Chris@0 345 /**
Chris@14 346 * @todo Implement this properly
Chris@0 347 */
Chris@14 348 private function canBeSerialized($variable): bool
Chris@0 349 {
Chris@14 350 if (!\is_object($variable)) {
Chris@14 351 return !\is_resource($variable);
Chris@0 352 }
Chris@0 353
Chris@0 354 if ($variable instanceof \stdClass) {
Chris@0 355 return true;
Chris@0 356 }
Chris@0 357
Chris@0 358 $class = new ReflectionClass($variable);
Chris@0 359
Chris@0 360 do {
Chris@0 361 if ($class->isInternal()) {
Chris@0 362 return $variable instanceof Serializable;
Chris@0 363 }
Chris@0 364 } while ($class = $class->getParentClass());
Chris@0 365
Chris@0 366 return true;
Chris@0 367 }
Chris@0 368 }