You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+72-1
Original file line number
Diff line number
Diff line change
@@ -5,6 +5,7 @@ The intention, at least initially, is that these extra language features are enf
5
5
6
6
**Language feature added:**
7
7
-[Friend](#friend)
8
+
-[InjectableVersion](#injectableVersion)
8
9
-[Package](#package)
9
10
-[Sealed](#sealed)
10
11
-[TestTag](#testtag)
@@ -16,8 +17,9 @@ The intention, at least initially, is that these extra language features are enf
16
17
-[PHPStan](#phpstan)
17
18
-[Psalm](#psalm)
18
19
-[New Language Features](#new-language-features)
19
-
-[Package](#package)
20
20
-[Friend](#friend)
21
+
-[InjectableVersion](#injectableVersion)
22
+
-[Package](#package)
21
23
-[Sealed](#sealed)
22
24
-[TestTag](#testtag)
23
25
-[Further examples](#further-examples)
@@ -271,6 +273,75 @@ NOTES:
271
273
- Assume all classes within a namespace is test code. See [namespace config option](https://github.com/DaveLiddament/phpstan-php-language-extensions#exclude-checks-based-on-test-namespace).
272
274
273
275
276
+
277
+
## InjectableVersion
278
+
279
+
The `#[InjectableVersion]` is used in conjunction with dependency injection.
280
+
`#[InjectableVersion]` is applied to a class or interface.
281
+
It denotes that it is this version and not any classes that implement/extend that should be used in the codebase.
282
+
283
+
E.g.
284
+
285
+
```php
286
+
287
+
#[InjectableVersion]
288
+
class PersonRepository {...} // This is the version that should be type hinted in constructors.
289
+
290
+
class DoctrinePersonRepository extends PersonRepository {...}
291
+
292
+
class PersonCreator {
293
+
public function __construct(
294
+
private PersonRepository $personRepository, // OK - using the injectable version
295
+
)
296
+
}
297
+
class PersonUpdater {
298
+
public function __construct(
299
+
private DoctrinePersonRepository $personRepository, // ERROR - not using the InjectableVersion
300
+
)
301
+
}
302
+
```
303
+
304
+
This also works for collections:
305
+
306
+
```php
307
+
308
+
#[InjectableVersion]
309
+
interface Validator {...} // This is the version that should be type hinted in constructors.
310
+
311
+
class NameValidator implements Validator {...}
312
+
class AddressValidator implements Validator {...}
313
+
314
+
class PersonValidator {
315
+
/** @param Validator[] $validators */
316
+
public function __construct(
317
+
private array $validators, // OK - using the injectable version
318
+
)
319
+
}
320
+
```
321
+
322
+
By default, only constructor arguments are checked. Most DI should be done via constructor injection.
323
+
324
+
In cases where dependencies are injected by methods that aren't constructors, the method must be marked with a `#[CheckInjectableVersion]`:
325
+
326
+
```php
327
+
328
+
#[InjectableVersion]
329
+
interface Logger {...}
330
+
331
+
class FileLogger implements Logger {...}
332
+
333
+
class MyService
334
+
{
335
+
#[CheckInjectableVersion]
336
+
public function setLogger(Logger $logger): void {} // OK - Injectable Version injected
337
+
338
+
public function addLogger(FileLogger $logger): void {} // No issue raised because addLogger doesn't have the #[CheckInjectableVersion] attribute.
339
+
}
340
+
341
+
```
342
+
343
+
344
+
274
345
## Further examples
275
346
276
347
More detailed examples of how to use attributes is found in [examples](examples/).
0 commit comments