This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare( strict_types = 1 ); |
||
4 | |||
5 | namespace Wikibase\Repo\Api; |
||
6 | |||
7 | use ApiBase; |
||
8 | use ApiUsageException; |
||
9 | use ArrayAccess; |
||
10 | use InvalidArgumentException; |
||
11 | use LogicException; |
||
12 | use MediaWiki\Permissions\PermissionManager; |
||
13 | use OutOfBoundsException; |
||
14 | use Status; |
||
15 | use Wikibase\DataModel\Entity\EntityDocument; |
||
16 | use Wikibase\DataModel\Entity\EntityId; |
||
17 | use Wikibase\DataModel\Entity\EntityIdParser; |
||
18 | use Wikibase\Lib\EntityFactory; |
||
19 | use Wikibase\Lib\FormatableSummary; |
||
20 | use Wikibase\Lib\Store\EntityRevisionLookup; |
||
21 | use Wikibase\Lib\Store\EntityStore; |
||
22 | use Wikibase\Lib\Store\LookupConstants; |
||
23 | use Wikibase\Lib\Store\StorageException; |
||
24 | use Wikibase\Repo\EditEntity\EditEntity; |
||
0 ignored issues
–
show
|
|||
25 | use Wikibase\Repo\EditEntity\MediawikiEditEntityFactory; |
||
26 | use Wikibase\Repo\SummaryFormatter; |
||
27 | |||
28 | /** |
||
29 | * Helper class for api modules to save entities. |
||
30 | * |
||
31 | * @license GPL-2.0-or-later |
||
32 | * @author Addshore |
||
33 | * @author Daniel Kinzler |
||
34 | */ |
||
35 | class EntitySavingHelper extends EntityLoadingHelper { |
||
36 | |||
37 | public const ASSIGN_FRESH_ID = 'assignFreshId'; |
||
38 | public const NO_FRESH_ID = 'noFreshId'; |
||
39 | |||
40 | /** |
||
41 | * @var SummaryFormatter |
||
42 | */ |
||
43 | private $summaryFormatter; |
||
44 | |||
45 | /** |
||
46 | * @var MediawikiEditEntityFactory |
||
47 | */ |
||
48 | private $editEntityFactory; |
||
49 | |||
50 | /** |
||
51 | * @var PermissionManager |
||
52 | */ |
||
53 | private $permissionManager; |
||
54 | |||
55 | /** |
||
56 | * Flags to pass to EditEntity::attemptSave; This is set by loadEntity() to EDIT_NEW |
||
57 | * for new entities, and EDIT_UPDATE for existing entities. |
||
58 | * |
||
59 | * @see EditEntity::attemptSave |
||
60 | * @see WikiPage::doEditContent |
||
61 | * |
||
62 | * @var int |
||
63 | */ |
||
64 | private $entitySavingFlags = 0; |
||
65 | |||
66 | /** |
||
67 | * Entity ID of the loaded entity. |
||
68 | * |
||
69 | * @var EntityId|null |
||
70 | */ |
||
71 | private $entityId = null; |
||
72 | |||
73 | /** |
||
74 | * Base revision ID, for loading the entity revision for editing, and for avoiding |
||
75 | * race conditions. |
||
76 | * |
||
77 | * @var int |
||
78 | */ |
||
79 | private $baseRevisionId = 0; |
||
80 | |||
81 | /** |
||
82 | * @var EntityFactory|null |
||
83 | */ |
||
84 | private $entityFactory = null; |
||
85 | |||
86 | /** |
||
87 | * @var EntityStore|null |
||
88 | */ |
||
89 | private $entityStore = null; |
||
90 | |||
91 | public function __construct( |
||
92 | ApiBase $apiModule, |
||
93 | EntityIdParser $idParser, |
||
94 | EntityRevisionLookup $entityRevisionLookup, |
||
95 | ApiErrorReporter $errorReporter, |
||
96 | SummaryFormatter $summaryFormatter, |
||
97 | MediawikiEditEntityFactory $editEntityFactory, |
||
98 | PermissionManager $permissionManager |
||
99 | ) { |
||
100 | parent::__construct( $apiModule, $idParser, $entityRevisionLookup, $errorReporter ); |
||
101 | |||
102 | $this->summaryFormatter = $summaryFormatter; |
||
103 | $this->editEntityFactory = $editEntityFactory; |
||
104 | $this->permissionManager = $permissionManager; |
||
105 | |||
106 | $this->defaultRetrievalMode = LookupConstants::LATEST_FROM_MASTER; |
||
107 | } |
||
108 | |||
109 | public function getBaseRevisionId(): int { |
||
110 | return $this->baseRevisionId; |
||
111 | } |
||
112 | |||
113 | public function getSaveFlags(): int { |
||
114 | return $this->entitySavingFlags; |
||
115 | } |
||
116 | |||
117 | public function getEntityFactory(): ?EntityFactory { |
||
118 | return $this->entityFactory; |
||
119 | } |
||
120 | |||
121 | public function setEntityFactory( EntityFactory $entityFactory ): void { |
||
122 | $this->entityFactory = $entityFactory; |
||
123 | } |
||
124 | |||
125 | public function getEntityStore(): ?EntityStore { |
||
126 | return $this->entityStore; |
||
127 | } |
||
128 | |||
129 | public function setEntityStore( EntityStore $entityStore ): void { |
||
130 | $this->entityStore = $entityStore; |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * @param EntityId|null $entityId ID of the entity to load. If not given, the ID is taken |
||
135 | * from the request parameters. If $entityId is given, the 'baserevid' parameter must |
||
136 | * belong to it. |
||
137 | * @param string $assignFreshId Whether to allow assigning entity ids to new entities. |
||
138 | * Either of the ASSIGN_FRESH_ID/NO_FRESH_ID constants. |
||
139 | * NOTE: We usually need to assign an ID early, for things like the ClaimIdGenerator. |
||
140 | * |
||
141 | * @throws ApiUsageException |
||
142 | * |
||
143 | * @return EntityDocument |
||
144 | */ |
||
145 | public function loadEntity( ?EntityId $entityId = null, $assignFreshId = self::ASSIGN_FRESH_ID ): EntityDocument { |
||
146 | if ( !in_array( $assignFreshId, [ self::ASSIGN_FRESH_ID, self::NO_FRESH_ID ] ) ) { |
||
147 | throw new InvalidArgumentException( |
||
148 | '$assignFreshId must be either of the EntitySavingHelper::ASSIGN_FRESH_ID/NO_FRESH_ID constants.' |
||
149 | ); |
||
150 | } |
||
151 | |||
152 | $params = $this->apiModule->extractRequestParams(); |
||
153 | |||
154 | if ( !$entityId ) { |
||
155 | $entityId = $this->getEntityIdFromParams( $params ); |
||
156 | } |
||
157 | |||
158 | // If a base revision is given, use if for consistency! |
||
159 | $baseRev = isset( $params['baserevid'] ) |
||
160 | ? (int)$params['baserevid'] |
||
161 | : 0; |
||
162 | |||
163 | if ( $entityId ) { |
||
164 | $entityRevision = $this->loadEntityRevision( $entityId, $baseRev ); |
||
165 | } else { |
||
166 | if ( $baseRev > 0 ) { |
||
167 | $this->errorReporter->dieError( |
||
0 ignored issues
–
show
The method
Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. ![]() |
|||
168 | 'Cannot load specific revision ' . $baseRev . ' if no entity is defined.', |
||
169 | 'param-illegal' |
||
170 | ); |
||
171 | } |
||
172 | |||
173 | $entityRevision = null; |
||
174 | } |
||
175 | |||
176 | $new = $params['new'] ?? null; |
||
177 | if ( $entityRevision === null ) { |
||
178 | if ( $baseRev > 0 ) { |
||
179 | $this->errorReporter->dieError( |
||
0 ignored issues
–
show
The method
Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. ![]() |
|||
180 | 'Could not find revision ' . $baseRev, |
||
181 | 'nosuchrevid' |
||
182 | ); |
||
183 | } |
||
184 | |||
185 | if ( !$this->isEntityCreationSupported() ) { |
||
186 | if ( !$entityId ) { |
||
187 | $this->errorReporter->dieError( |
||
0 ignored issues
–
show
The method
Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. ![]() |
|||
188 | 'No entity ID provided, and entity cannot be created', |
||
189 | 'no-entity-id' |
||
190 | ); |
||
191 | } else { |
||
192 | $this->errorReporter->dieWithError( [ 'no-such-entity', $entityId ], |
||
0 ignored issues
–
show
array('no-such-entity', $entityId) is of type array<integer,string|obj...l\\Entity\\EntityId>"}> , but the function expects a string|array<integer,str...bject<MessageSpecifier> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
193 | 'no-such-entity' |
||
194 | ); |
||
195 | } |
||
196 | } |
||
197 | |||
198 | if ( !$entityId && !$new ) { |
||
199 | $this->errorReporter->dieError( |
||
0 ignored issues
–
show
The method
Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. ![]() |
|||
200 | 'No entity was identified, nor was creation requested', |
||
201 | 'no-entity-id' |
||
202 | ); |
||
203 | } |
||
204 | |||
205 | if ( $entityId && !$this->entityStore->canCreateWithCustomId( $entityId ) ) { |
||
206 | $this->errorReporter->dieWithError( [ 'no-such-entity', $entityId ], |
||
0 ignored issues
–
show
array('no-such-entity', $entityId) is of type array<integer,string|obj...l\\Entity\\EntityId>"}> , but the function expects a string|array<integer,str...bject<MessageSpecifier> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
207 | 'no-such-entity' |
||
208 | ); |
||
209 | } |
||
210 | |||
211 | $entity = $this->createEntity( $new, $entityId, $assignFreshId ); |
||
212 | |||
213 | $this->entitySavingFlags = EDIT_NEW; |
||
214 | $this->baseRevisionId = 0; |
||
215 | } else { |
||
216 | $this->entitySavingFlags = EDIT_UPDATE; |
||
217 | $this->baseRevisionId = $entityRevision->getRevisionId(); |
||
218 | $entity = $entityRevision->getEntity(); |
||
219 | } |
||
220 | |||
221 | // remember the entity ID |
||
222 | $this->entityId = $entity->getId(); |
||
223 | |||
224 | return $entity; |
||
225 | } |
||
226 | |||
227 | private function isEntityCreationSupported(): bool { |
||
228 | return $this->entityStore !== null && $this->entityFactory !== null; |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Create an empty entity. |
||
233 | * |
||
234 | * @param string|null $entityType The type of entity to create. Optional if an ID is given. |
||
235 | * @param EntityId|null $customId Optionally assigns a specific ID instead of generating a new |
||
236 | * one. |
||
237 | * @param string $assignFreshId Either of the ASSIGN_FRESH_ID/NO_FRESH_ID constants |
||
238 | * NOTE: We usually need to assign an ID early, for things like the ClaimIdGenerator. |
||
239 | * |
||
240 | * @throws InvalidArgumentException when entity type and ID are given but do not match. |
||
241 | * @throws ApiUsageException |
||
242 | * @throws LogicException |
||
243 | * @return EntityDocument |
||
244 | */ |
||
245 | private function createEntity( $entityType, EntityId $customId = null, $assignFreshId = self::ASSIGN_FRESH_ID ): EntityDocument { |
||
246 | if ( $customId ) { |
||
247 | $entityType = $customId->getEntityType(); |
||
248 | } elseif ( !$entityType ) { |
||
0 ignored issues
–
show
The expression
$entityType of type string|null is loosely compared to false ; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
249 | $this->errorReporter->dieError( |
||
0 ignored issues
–
show
The method
Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. ![]() |
|||
250 | "No entity type provided for creation!", |
||
251 | 'no-entity-type' |
||
252 | ); |
||
253 | |||
254 | throw new LogicException( 'ApiErrorReporter::dieError did not throw an exception' ); |
||
255 | } |
||
256 | |||
257 | try { |
||
258 | $entity = $this->entityFactory->newEmpty( $entityType ); |
||
259 | } catch ( OutOfBoundsException $ex ) { |
||
260 | $this->errorReporter->dieError( |
||
0 ignored issues
–
show
The method
Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. ![]() |
|||
261 | "No such entity type: '$entityType'", |
||
262 | 'no-such-entity-type' |
||
263 | ); |
||
264 | |||
265 | throw new LogicException( 'ApiErrorReporter::dieError did not throw an exception' ); |
||
266 | } |
||
267 | |||
268 | if ( $customId !== null ) { |
||
269 | if ( !$this->entityStore->canCreateWithCustomId( $customId ) ) { |
||
270 | $this->errorReporter->dieError( |
||
0 ignored issues
–
show
The method
Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. ![]() |
|||
271 | "Cannot create entity with ID: '$customId'", |
||
272 | 'bad-entity-id' |
||
273 | ); |
||
274 | |||
275 | throw new LogicException( 'ApiErrorReporter::dieError did not throw an exception' ); |
||
276 | } |
||
277 | |||
278 | $entity->setId( $customId ); |
||
279 | } elseif ( $assignFreshId === self::ASSIGN_FRESH_ID ) { |
||
280 | try { |
||
281 | $this->entityStore->assignFreshId( $entity ); |
||
282 | } catch ( StorageException $e ) { |
||
283 | $this->errorReporter->dieError( |
||
0 ignored issues
–
show
The method
Wikibase\Repo\Api\ApiErrorReporter::dieError() has been deprecated with message: Use dieWithError() instead.
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead. ![]() |
|||
284 | 'Cannot automatically assign ID: ' . $e->getMessage(), |
||
285 | 'no-automatic-entity-id' |
||
286 | ); |
||
287 | |||
288 | throw new LogicException( 'ApiErrorReporter::dieError did not throw an exception' ); |
||
289 | } |
||
290 | |||
291 | } |
||
292 | |||
293 | return $entity; |
||
294 | } |
||
295 | |||
296 | /** |
||
297 | * Attempts to save the new entity content, while first checking for permissions, |
||
298 | * edit conflicts, etc. Saving is done via EditEntityHandler::attemptSave(). |
||
299 | * |
||
300 | * This method automatically takes into account several parameters: |
||
301 | * * 'bot' for setting the bot flag |
||
302 | * * 'baserevid' for determining the edit's base revision for conflict resolution |
||
303 | * * 'token' for the edit token |
||
304 | * * 'tags' for change tags, assuming they were already permission checked by ApiBase |
||
305 | * (i.e. PARAM_TYPE => 'tags') |
||
306 | * |
||
307 | * If an error occurs, it is automatically reported and execution of the API module |
||
308 | * is terminated using the ApiErrorReporter (via handleStatus()). If there were any |
||
309 | * warnings, they will automatically be included in the API call's output (again, via |
||
310 | * handleStatus()). |
||
311 | * |
||
312 | * @param EntityDocument $entity The entity to save |
||
313 | * @param string|FormatableSummary $summary The edit summary |
||
314 | * @param int $flags The edit flags (see WikiPage::doEditContent) |
||
315 | * |
||
316 | * @throws LogicException if not in write mode |
||
317 | * @return Status the status of the save operation, as returned by EditEntityHandler::attemptSave() |
||
318 | * @see EditEntityHandler::attemptSave() |
||
319 | */ |
||
320 | public function attemptSaveEntity( EntityDocument $entity, $summary, int $flags = 0 ): Status { |
||
321 | if ( !$this->apiModule->isWriteMode() ) { |
||
322 | // sanity/safety check |
||
323 | throw new LogicException( |
||
324 | 'attemptSaveEntity() cannot be used by API modules that do not return true from isWriteMode()!' |
||
325 | ); |
||
326 | } |
||
327 | |||
328 | if ( $this->entityId !== null && !$entity->getId()->equals( $this->entityId ) ) { |
||
329 | // sanity/safety check |
||
330 | throw new LogicException( |
||
331 | 'attemptSaveEntity() was expecting to be called on ' |
||
332 | . $this->entityId->getSerialization() . '!' |
||
333 | ); |
||
334 | } |
||
335 | |||
336 | if ( $summary instanceof FormatableSummary ) { |
||
337 | $summary = $this->summaryFormatter->formatSummary( $summary ); |
||
338 | } |
||
339 | |||
340 | $params = $this->apiModule->extractRequestParams(); |
||
341 | $user = $this->apiModule->getContext()->getUser(); |
||
342 | |||
343 | if ( isset( $params['bot'] ) && $params['bot'] && |
||
344 | $this->permissionManager->userHasRight( $user, 'bot' ) |
||
345 | ) { |
||
346 | $flags |= EDIT_FORCE_BOT; |
||
347 | } |
||
348 | |||
349 | if ( !$this->baseRevisionId ) { |
||
350 | $this->baseRevisionId = isset( $params['baserevid'] ) ? (int)$params['baserevid'] : 0; |
||
351 | } |
||
352 | |||
353 | $tags = $params['tags'] ?? []; |
||
354 | |||
355 | $editEntityHandler = $this->editEntityFactory->newEditEntity( |
||
356 | $user, |
||
357 | $entity->getId(), |
||
358 | $this->baseRevisionId, |
||
359 | true |
||
360 | ); |
||
361 | |||
362 | $token = $this->evaluateTokenParam( $params ); |
||
363 | |||
364 | $status = $editEntityHandler->attemptSave( |
||
365 | $entity, |
||
366 | $summary, |
||
367 | $this->entitySavingFlags | $flags, |
||
368 | $token, |
||
0 ignored issues
–
show
It seems like
$token defined by $this->evaluateTokenParam($params) on line 362 can also be of type null ; however, Wikibase\Repo\EditEntity\EditEntity::attemptSave() does only seem to accept string|boolean , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
369 | null, |
||
370 | $tags |
||
371 | ); |
||
372 | |||
373 | $this->handleSaveStatus( $status ); |
||
374 | return $status; |
||
375 | } |
||
376 | |||
377 | /** |
||
378 | * @param array $params |
||
379 | * |
||
380 | * @return string|bool|null Token string, or false if not needed, or null if not set. |
||
381 | */ |
||
382 | private function evaluateTokenParam( array $params ) { |
||
383 | if ( !$this->apiModule->needsToken() ) { |
||
384 | // False disables the token check. |
||
385 | return false; |
||
386 | } |
||
387 | |||
388 | // Null fails the token check. |
||
389 | return $params['token'] ?? null; |
||
390 | } |
||
391 | |||
392 | /** |
||
393 | * Signal errors and warnings from a save operation to the API call's output. |
||
394 | * This is much like handleStatus(), but specialized for Status objects returned by |
||
395 | * EditEntityHandler::attemptSave(). In particular, the 'errorFlags' and 'errorCode' fields |
||
396 | * from the status value are used to determine the error code to return to the caller. |
||
397 | * |
||
398 | * @note this function may or may not return normally, depending on whether |
||
399 | * the status is fatal or not. |
||
400 | * |
||
401 | * @see handleStatus(). |
||
402 | * |
||
403 | * @param Status $status The status to report |
||
404 | */ |
||
405 | private function handleSaveStatus( Status $status ): void { |
||
406 | $value = $status->getValue(); |
||
407 | $errorCode = null; |
||
408 | |||
409 | if ( $this->isArrayLike( $value ) && isset( $value['errorCode'] ) ) { |
||
410 | $errorCode = $value['errorCode']; |
||
411 | } else { |
||
412 | $editError = 0; |
||
413 | |||
414 | if ( $this->isArrayLike( $value ) && isset( $value['errorFlags'] ) ) { |
||
415 | $editError = $value['errorFlags']; |
||
416 | } |
||
417 | |||
418 | if ( $editError & EditEntity::TOKEN_ERROR ) { |
||
419 | $errorCode = 'badtoken'; |
||
420 | } elseif ( $editError & EditEntity::EDIT_CONFLICT_ERROR ) { |
||
421 | $errorCode = 'editconflict'; |
||
422 | } elseif ( $editError & EditEntity::ANY_ERROR ) { |
||
423 | $errorCode = 'failed-save'; |
||
424 | } |
||
425 | } |
||
426 | |||
427 | //NOTE: will just add warnings or do nothing if there's no error |
||
428 | $this->handleStatus( $status, $errorCode ); |
||
429 | } |
||
430 | |||
431 | /** |
||
432 | * Checks whether accessing array keys is safe, with e.g. @see DeprecatablePropertyArray |
||
433 | */ |
||
434 | private function isArrayLike( $value ): bool { |
||
435 | return is_array( $value ) || $value instanceof ArrayAccess; |
||
436 | } |
||
437 | |||
438 | /** |
||
439 | * Include messages from a Status object in the API call's output. |
||
440 | * |
||
441 | * An ApiErrorHandler is used to report the status, if necessary. |
||
442 | * If $status->isOK() is false, this method will terminate with an ApiUsageException. |
||
443 | * |
||
444 | * @param Status $status The status to report |
||
445 | * @param string $errorCode The API error code to use in case $status->isOK() returns false |
||
446 | * |
||
447 | * @throws ApiUsageException If $status->isOK() returns false. |
||
448 | */ |
||
449 | private function handleStatus( Status $status, $errorCode ): void { |
||
450 | if ( $status->isGood() ) { |
||
451 | return; |
||
452 | } elseif ( $status->isOK() ) { |
||
453 | $this->errorReporter->reportStatusWarnings( $status ); |
||
454 | } else { |
||
455 | $this->errorReporter->reportStatusWarnings( $status ); |
||
456 | $this->errorReporter->dieStatus( $status, $errorCode ); |
||
457 | } |
||
458 | } |
||
459 | |||
460 | } |
||
461 |
Let’s assume that you have a directory layout like this:
and let’s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: