• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / di / 6739035766

02 Nov 2023 10:44PM UTC coverage: 52.037% (-41.8%) from 93.846%
6739035766

push

github

dg
x

1009 of 1939 relevant lines covered (52.04%)

0.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

3.57
/src/DI/DependencyChecker.php
1
<?php
2

3
/**
4
 * This file is part of the Nette Framework (https://nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
declare(strict_types=1);
9

10
namespace Nette\DI;
11

12
use Nette;
13
use Nette\Utils\Reflection;
14
use Nette\Utils\Type;
15
use ReflectionClass;
16
use ReflectionMethod;
17

18

19
/**
20
 * Cache dependencies checker.
21
 */
22
class DependencyChecker
23
{
24
        use Nette\SmartObject;
25

26
        public const Version = 1;
27

28
        /** @deprecated use DependencyChecker::Version */
29
        public const VERSION = self::Version;
30

31
        /** @var array of ReflectionClass|\ReflectionFunctionAbstract|string */
32
        private $dependencies = [];
33

34

35
        /**
36
         * Adds dependencies to the list.
37
         * @return static
38
         */
39
        public function add(array $deps)
1✔
40
        {
41
                $this->dependencies = array_merge($this->dependencies, $deps);
1✔
42
                return $this;
1✔
43
        }
44

45

46
        /**
47
         * Exports dependencies.
48
         */
49
        public function export(): array
50
        {
51
                $files = $phpFiles = $classes = $functions = [];
×
52
                foreach ($this->dependencies as $dep) {
×
53
                        if (is_string($dep)) {
×
54
                                $files[] = $dep;
×
55

56
                        } elseif ($dep instanceof ReflectionClass) {
×
57
                                if (empty($classes[$name = $dep->name])) {
×
58
                                        $all = [$name] + class_parents($name) + class_implements($name);
×
59
                                        foreach ($all as &$item) {
×
60
                                                $all += class_uses($item);
×
61
                                                $phpFiles[] = (new ReflectionClass($item))->getFileName();
×
62
                                                $classes[$item] = true;
×
63
                                        }
64
                                }
65
                        } elseif ($dep instanceof \ReflectionFunctionAbstract) {
×
66
                                $phpFiles[] = $dep->getFileName();
×
67
                                $functions[] = rtrim(Reflection::toString($dep), '()');
×
68

69
                        } else {
70
                                throw new Nette\InvalidStateException(sprintf('Unexpected dependency %s', gettype($dep)));
×
71
                        }
72
                }
73

74
                $classes = array_keys($classes);
×
75
                $functions = array_unique($functions, SORT_REGULAR);
×
76
                $hash = self::calculateHash($classes, $functions);
×
77
                $files = @array_map('filemtime', array_combine($files, $files)); // @ - file may not exist
×
78
                $phpFiles = @array_map('filemtime', array_combine($phpFiles, $phpFiles)); // @ - file may not exist
×
79
                return [self::Version, $files, $phpFiles, $classes, $functions, $hash];
×
80
        }
81

82

83
        /**
84
         * Are dependencies expired?
85
         */
86
        public static function isExpired(
87
                int $version,
88
                array $files,
89
                array &$phpFiles,
90
                array $classes,
91
                array $functions,
92
                string $hash
93
        ): bool
94
        {
95
                try {
96
                        $currentFiles = @array_map('filemtime', array_combine($tmp = array_keys($files), $tmp)); // @ - files may not exist
×
97
                        $origPhpFiles = $phpFiles;
×
98
                        $phpFiles = @array_map('filemtime', array_combine($tmp = array_keys($phpFiles), $tmp)); // @ - files may not exist
×
99
                        return $version !== self::Version
×
100
                                || $files !== $currentFiles
×
101
                                || ($phpFiles !== $origPhpFiles && $hash !== self::calculateHash($classes, $functions));
×
102
                } catch (\ReflectionException $e) {
×
103
                        return true;
×
104
                }
105
        }
106

107

108
        private static function calculateHash(array $classes, array $functions): string
109
        {
110
                $hash = [];
×
111
                foreach ($classes as $name) {
×
112
                        $class = new ReflectionClass($name);
×
113
                        $hash[] = [
×
114
                                $name,
×
115
                                Reflection::getUseStatements($class),
×
116
                                $class->isAbstract(),
×
117
                                get_parent_class($name),
×
118
                                class_implements($name),
×
119
                                class_uses($name),
×
120
                        ];
121

122
                        foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
×
123
                                if ($prop->getDeclaringClass() == $class) { // intentionally ==
×
124
                                        $hash[] = [
×
125
                                                $name,
×
126
                                                $prop->name,
×
127
                                                $prop->getDocComment(),
×
128
                                                (string) Type::fromReflection($prop),
×
129
                                                PHP_VERSION_ID >= 80000 ? count($prop->getAttributes(Attributes\Inject::class)) : null,
×
130
                                        ];
131
                                }
132
                        }
133

134
                        foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
×
135
                                if ($method->getDeclaringClass() == $class) { // intentionally ==
×
136
                                        $hash[] = [
×
137
                                                $name,
×
138
                                                $method->name,
×
139
                                                $method->getDocComment(),
×
140
                                                self::hashParameters($method),
×
141
                                                (string) Type::fromReflection($method),
×
142
                                        ];
143
                                }
144
                        }
145
                }
146

147
                $flip = array_flip($classes);
×
148
                foreach ($functions as $name) {
×
149
                        if (strpos($name, '::')) {
×
150
                                $method = new ReflectionMethod($name);
×
151
                                $class = $method->getDeclaringClass();
×
152
                                if (isset($flip[$class->name])) {
×
153
                                        continue;
×
154
                                }
155

156
                                $uses = Reflection::getUseStatements($class);
×
157
                        } else {
158
                                $method = new \ReflectionFunction($name);
×
159
                                $uses = null;
×
160
                        }
161

162
                        $hash[] = [
×
163
                                $name,
×
164
                                $uses,
×
165
                                $method->getDocComment(),
×
166
                                self::hashParameters($method),
×
167
                                (string) Type::fromReflection($method),
×
168
                        ];
169
                }
170

171
                return md5(serialize($hash));
×
172
        }
173

174

175
        private static function hashParameters(\ReflectionFunctionAbstract $method): array
176
        {
177
                $res = [];
×
178
                foreach ($method->getParameters() as $param) {
×
179
                        $res[] = [
×
180
                                $param->name,
×
181
                                (string) Type::fromReflection($param),
×
182
                                $param->isVariadic(),
×
183
                                $param->isDefaultValueAvailable()
×
184
                                        ? is_object($tmp = Reflection::getParameterDefaultValue($param)) ? ['object' => get_class($tmp)] : ['value' => $tmp]
×
185
                                        : null,
186
                        ];
187
                }
188

189
                return $res;
×
190
        }
191
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc