8
8
9
9
use function array_key_exists ;
10
10
use function array_reduce ;
11
- use function basename ;
12
11
use function debug_backtrace ;
13
12
use function sprintf ;
14
13
use function strpos ;
14
+ use function strrpos ;
15
+ use function substr ;
15
16
use function trigger_error ;
16
17
17
18
use const DEBUG_BACKTRACE_IGNORE_ARGS ;
19
+ use const DIRECTORY_SEPARATOR ;
18
20
use const E_USER_DEPRECATED ;
19
21
20
22
/**
21
23
* Manages Deprecation logging in different ways.
22
24
*
23
- * By default triggered exceptions are not logged, only the amount of
24
- * deprecations triggered can be queried with `Deprecation::getUniqueTriggeredDeprecationsCount()`.
25
+ * By default triggered exceptions are not logged.
25
26
*
26
27
* To enable different deprecation logging mechanisms you can call the
27
28
* following methods:
28
29
*
29
- * - Uses trigger_error with E_USER_DEPRECATED
30
- * \Doctrine\Deprecations\Deprecation::enableWithTriggerError ();
30
+ * - Minimal collection of deprecations via getTriggeredDeprecations()
31
+ * \Doctrine\Deprecations\Deprecation::enableTrackingDeprecations ();
31
32
*
32
33
* - Uses @trigger_error with E_USER_DEPRECATED
33
- * \Doctrine\Deprecations\Deprecation::enableWithSuppressedTriggerError ();
34
+ * \Doctrine\Deprecations\Deprecation::enableWithTriggerError ();
34
35
*
35
36
* - Sends deprecation messages via a PSR-3 logger
36
37
* \Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
37
38
*
38
- * Packages that trigger deprecations should use the `trigger()` method.
39
+ * Packages that trigger deprecations should use the `trigger()` or
40
+ * `triggerIfCalledFromOutside()` methods.
39
41
*/
40
42
class Deprecation
41
43
{
42
- private const TYPE_NONE = 0 ;
43
- private const TYPE_TRIGGER_ERROR = 1 ;
44
- private const TYPE_TRIGGER_SUPPRESSED_ERROR = 2 ;
45
- private const TYPE_PSR_LOGGER = 3 ;
44
+ private const TYPE_NONE = 0 ;
45
+ private const TYPE_TRACK_DEPRECATIONS = 1 ;
46
+ private const TYPE_TRIGGER_ERROR = 2 ;
47
+ private const TYPE_PSR_LOGGER = 4 ;
46
48
47
49
/** @var int */
48
50
private static $ type = self ::TYPE_NONE ;
@@ -60,7 +62,7 @@ class Deprecation
60
62
private static $ deduplication = true ;
61
63
62
64
/**
63
- * Trigger a deprecation for the given package, starting with given version .
65
+ * Trigger a deprecation for the given package and identfier .
64
66
*
65
67
* The link should point to a Github issue or Wiki entry detailing the
66
68
* deprecation. It is additionally used to de-duplicate the trigger of the
@@ -70,6 +72,10 @@ class Deprecation
70
72
*/
71
73
public static function trigger (string $ package , string $ link , string $ message , ...$ args ): void
72
74
{
75
+ if (self ::$ type === self ::TYPE_NONE ) {
76
+ return ;
77
+ }
78
+
73
79
if (array_key_exists ($ link , self ::$ ignoredLinks )) {
74
80
self ::$ ignoredLinks [$ link ]++;
75
81
} else {
@@ -80,12 +86,6 @@ public static function trigger(string $package, string $link, string $message, .
80
86
return ;
81
87
}
82
88
83
- // do not move this condition to the top, because we still want to
84
- // count occcurences of deprecations even when we are not logging them.
85
- if (self ::$ type === self ::TYPE_NONE ) {
86
- return ;
87
- }
88
-
89
89
if (isset (self ::$ ignoredPackages [$ package ])) {
90
90
return ;
91
91
}
@@ -98,16 +98,32 @@ public static function trigger(string $package, string $link, string $message, .
98
98
}
99
99
100
100
/**
101
+ * Trigger a deprecation for the given package and identifier when called from outside.
102
+ *
103
+ * "Outside" means we assume that $package is currently installed as a
104
+ * dependency and the caller is not a file in that package. When $package
105
+ * is installed as a root package then deprecations triggered from the
106
+ * tests folder are also considered "outside".
107
+ *
108
+ * This deprecation method assumes that you are using Composer to install
109
+ * the dependency and are using the default /vendor/ folder and not a
110
+ * Composer plugin to change the install location. The assumption is also
111
+ * that $package is the exact composer packge name.
112
+ *
113
+ * Compared to {@link trigger()} this method causes some overhead when
114
+ * deprecation tracking is enabled even during deduplication, because it
115
+ * needs to call {@link debug_backtrace()}
116
+ *
101
117
* @param mixed $args
102
118
*/
103
119
public static function triggerIfCalledFromOutside (string $ package , string $ link , string $ message , ...$ args ): void
104
120
{
121
+ if (self ::$ type === self ::TYPE_NONE ) {
122
+ return ;
123
+ }
124
+
105
125
$ backtrace = debug_backtrace (DEBUG_BACKTRACE_IGNORE_ARGS , 2 );
106
126
107
- // "outside" means we assume that $package is currently installed as a
108
- // dependency and the caller is not a file in that package.
109
- // When $package is installed as a root package, then this deprecation
110
- // is always ignored
111
127
// first check that the caller is not from a tests folder, in which case we always let deprecations pass
112
128
if (strpos ($ backtrace [1 ]['file ' ], '/tests/ ' ) === false ) {
113
129
if (strpos ($ backtrace [0 ]['file ' ], '/vendor/ ' . $ package . '/ ' ) === false ) {
@@ -129,12 +145,6 @@ public static function triggerIfCalledFromOutside(string $package, string $link,
129
145
return ;
130
146
}
131
147
132
- // do not move this condition to the top, because we still want to
133
- // count occcurences of deprecations even when we are not logging them.
134
- if (self ::$ type === self ::TYPE_NONE ) {
135
- return ;
136
- }
137
-
138
148
if (isset (self ::$ ignoredPackages [$ package ])) {
139
149
return ;
140
150
}
@@ -149,56 +159,61 @@ public static function triggerIfCalledFromOutside(string $package, string $link,
149
159
*/
150
160
private static function delegateTriggerToBackend (string $ message , array $ backtrace , string $ link , string $ package ): void
151
161
{
152
- if (self ::$ type === self ::TYPE_TRIGGER_ERROR ) {
153
- $ message .= sprintf (
154
- ' (%s:%d called by %s:%d, %s, package %s) ' ,
155
- basename ($ backtrace [0 ]['file ' ]),
156
- $ backtrace [0 ]['line ' ],
157
- basename ($ backtrace [1 ]['file ' ]),
158
- $ backtrace [1 ]['line ' ],
159
- $ link ,
160
- $ package
161
- );
162
-
163
- trigger_error ($ message , E_USER_DEPRECATED );
164
- } elseif (self ::$ type === self ::TYPE_TRIGGER_SUPPRESSED_ERROR ) {
165
- $ message .= sprintf (
166
- ' (%s:%d called by %s:%d, %s, package %s) ' ,
167
- basename ($ backtrace [0 ]['file ' ]),
168
- $ backtrace [0 ]['line ' ],
169
- basename ($ backtrace [1 ]['file ' ]),
170
- $ backtrace [1 ]['line ' ],
171
- $ link ,
172
- $ package
173
- );
174
-
175
- @trigger_error ($ message , E_USER_DEPRECATED );
176
- } elseif (self ::$ type === self ::TYPE_PSR_LOGGER ) {
162
+ if ((self ::$ type & self ::TYPE_PSR_LOGGER ) > 0 ) {
177
163
$ context = [
178
164
'file ' => $ backtrace [0 ]['file ' ],
179
165
'line ' => $ backtrace [0 ]['line ' ],
166
+ 'package ' => $ package ,
167
+ 'link ' => $ link ,
180
168
];
181
169
182
- $ context ['package ' ] = $ package ;
183
- $ context ['link ' ] = $ link ;
184
-
185
170
self ::$ logger ->notice ($ message , $ context );
186
171
}
172
+
173
+ if (! ((self ::$ type & self ::TYPE_TRIGGER_ERROR ) > 0 )) {
174
+ return ;
175
+ }
176
+
177
+ $ message .= sprintf (
178
+ ' (%s:%d called by %s:%d, %s, package %s) ' ,
179
+ self ::basename ($ backtrace [0 ]['file ' ]),
180
+ $ backtrace [0 ]['line ' ],
181
+ self ::basename ($ backtrace [1 ]['file ' ]),
182
+ $ backtrace [1 ]['line ' ],
183
+ $ link ,
184
+ $ package
185
+ );
186
+
187
+ @trigger_error ($ message , E_USER_DEPRECATED );
187
188
}
188
189
189
- public static function enableWithTriggerError (): void
190
+ /**
191
+ * A non-local-aware version of PHPs basename function.
192
+ */
193
+ private static function basename (string $ filename ): string
190
194
{
191
- self ::$ type = self ::TYPE_TRIGGER_ERROR ;
195
+ $ pos = strrpos ($ filename , DIRECTORY_SEPARATOR );
196
+
197
+ if ($ pos === false ) {
198
+ return $ filename ;
199
+ }
200
+
201
+ return substr ($ filename , $ pos + 1 );
192
202
}
193
203
194
- public static function enableWithSuppressedTriggerError (): void
204
+ public static function enableTrackingDeprecations (): void
205
+ {
206
+ self ::$ type |= self ::TYPE_TRACK_DEPRECATIONS ;
207
+ }
208
+
209
+ public static function enableWithTriggerError (): void
195
210
{
196
- self ::$ type = self ::TYPE_TRIGGER_SUPPRESSED_ERROR ;
211
+ self ::$ type | = self ::TYPE_TRIGGER_ERROR ;
197
212
}
198
213
199
214
public static function enableWithPsrLogger (LoggerInterface $ logger ): void
200
215
{
201
- self ::$ type = self ::TYPE_PSR_LOGGER ;
216
+ self ::$ type | = self ::TYPE_PSR_LOGGER ;
202
217
self ::$ logger = $ logger ;
203
218
}
204
219
0 commit comments