├── .gitignore
├── resources
└── cover.png
├── phpstan.neon
├── src
├── InjectableVersion.php
├── CheckInjectableVersion.php
├── Override.php
├── NamespaceVisibility.php
├── Package.php
├── TestTag.php
├── Sealed.php
├── Friend.php
├── RestrictTraitTo.php
└── MustUseResult.php
├── examples
├── sealed
│ ├── sealedClasses.php
│ └── sealedInterfaces.php
├── testTag
│ ├── testTagOnConstructorIgnoredInTestClass.php
│ ├── testTagClassOnConstructorIgnoredInTestClass.php
│ ├── testTagOnStaticMethodIgnoredInTestClass.php
│ ├── testTagClassOnStaticMethodIgnoredInTestClass.php
│ ├── testTagClassOnMethodIgnoredInTestClass.php
│ ├── testTagOnMethodIgnoredInTestClass.php
│ ├── testTagOnMethod.php
│ ├── testTagOnConstructor.php
│ ├── testTagOnStaticMethod.php
│ ├── testTagClassOnMethod.php
│ ├── testTagOnStaticMethodIgnoredInTestNamespace.php
│ ├── testTagOnConstructorIgnoredInTestNamespace.php
│ ├── testTagOnMethodIgnoredInTestNamespace.php
│ ├── testTagClassOnConstructor.php
│ └── testTagClassOnStaticMethod.php
├── friend
│ ├── friendRulesIgnoredForTestClass.php
│ ├── friendOnDifferentNamespace.php
│ ├── multipleFriends.php
│ ├── friendRulesIgnoredForTestNamespace.php
│ ├── friendOnConstructor.php
│ ├── friendOnClass.php
│ ├── friendOnStaticMethod.php
│ └── friendOnMethod.php
├── injectableVersion
│ ├── InjectableVersionOnInterface.php
│ ├── InjectableVersionOnExtendsThenImplements.php
│ ├── InjectableVersionOnClass.php
│ ├── InjectableVersionRulesIgnoredForTestNamespace.php
│ ├── MultipleLevelsOfInheritanceNoInjectableVersionOnClass.php
│ ├── MultipleLevelsOfInheritanceNoInjectableVersionOnInterface.php
│ ├── IterableInjectableVersion.php
│ ├── MultipleLevelsOfInheritanceInjectableVersionOnInterface.php
│ └── InjectableVersionCheckOnMethod.php
├── mustUseResult
│ ├── mustUseResultOnStaticMethod.php
│ └── mustUseResultOnMethod.php
├── package
│ ├── packageRulesIgnoredForTestClass.php
│ ├── packageRulesIgnoredForTestNamespace.php
│ ├── packageOnConstructor.php
│ ├── packageOnMethod.php
│ ├── packageOnStaticMethod.php
│ └── packageOnClass.php
├── namespaceVisibility
│ ├── namespaceVisibilityRulesIgnoredForTestClass.php
│ ├── namespaceVisibilityRulesIgnoredForTestNamespace.php
│ ├── namespaceVisibilityOnStaticMethodExcludeSubNamespaces.php
│ ├── namespaceVisibilityOnConstructorForDifferentNamespaces.php
│ ├── namespaceVisibilityOnStaticMethodForDifferentNamespaces.php
│ ├── namespaceVisibilityOnMethodForDifferentNamespace.php
│ ├── namespaceVisibilityOnClassForDifferentNamespaces.php
│ ├── namespaceVisibilityOnClassExcludeSubNamespaces.php
│ ├── namespaceVisibilityOnMethodExcludeSubNamespace.php
│ ├── namespaceVisibilityOnConstructorExcludeSubNamespaces.php
│ ├── namespaceVisibilityOnConstructor.php
│ ├── namespaceVisibilityOnMethod.php
│ ├── namespaceVisibilityOnStaticMethod.php
│ └── namespaceVisibilityOnClass.php
├── override
│ ├── overrideOnClass.php
│ ├── overrideOnInterface.php
│ └── overrideRfcExamples.php
└── restrictTraitTo
│ └── restrictTraitTo.php
├── psalm.xml
├── .php-cs-fixer.php
├── LICENSE.md
├── composer.json
├── .github
└── workflows
│ └── full-checks.yml
├── CONTRIBUTING.md
├── README.md
└── composer.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .php-cs-fixer.cache
3 | .vagrant
4 | Vagrantfile
5 | vendor/
6 |
--------------------------------------------------------------------------------
/resources/cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveLiddament/php-language-extensions/HEAD/resources/cover.png
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: max
3 | paths:
4 | - src
5 |
6 | ignoreErrors:
7 | - '#^Constructor of class DaveLiddament\\PhpLanguageExtensions\\[a-zA-Z]+ has an unused parameter \$[a-zA-Z]+\.$#'
8 |
--------------------------------------------------------------------------------
/src/InjectableVersion.php:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/examples/testTag/testTagClassOnMethodIgnoredInTestClass.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK - Called from Test class
22 | }
23 | }
24 |
25 |
26 |
--------------------------------------------------------------------------------
/examples/testTag/testTagOnMethodIgnoredInTestClass.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK - Called from Test class
23 | }
24 | }
25 |
26 |
27 |
--------------------------------------------------------------------------------
/examples/friend/friendRulesIgnoredForTestClass.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: calling from a class with a name ending Test
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/examples/injectableVersion/InjectableVersionOnInterface.php:
--------------------------------------------------------------------------------
1 | updateName(); // ERROR
19 | }
20 | }
21 |
22 | class Updater
23 | {
24 | public function updater(Person $person): void
25 | {
26 | $person->updateName(); // ERROR
27 | }
28 | }
29 |
30 | $person = new Person();
31 | $person->updateName(); // ERROR
32 |
33 |
--------------------------------------------------------------------------------
/examples/testTag/testTagOnConstructor.php:
--------------------------------------------------------------------------------
1 | update(); // OK: Builder a friend of Employee
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/examples/testTag/testTagOnStaticMethod.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK - whole class is marked with TestTag, so OK to call methods within it.
19 | }
20 | }
21 |
22 | class Updater
23 | {
24 | public function updater(Person $person): void
25 | {
26 | $person->updateName(); // ERROR
27 | }
28 | }
29 |
30 | $person = new Person();
31 | $person->updateName(); // ERROR
32 |
33 |
--------------------------------------------------------------------------------
/examples/testTag/testTagOnStaticMethodIgnoredInTestNamespace.php:
--------------------------------------------------------------------------------
1 | dontNeedToUseResult(); // OK
27 |
28 | $class->mustUseResult(); // ERROR
29 |
30 | echo $class->mustUseResult(); // OK;
31 |
32 | $value = 1 + $class->mustUseResult(); // OK
33 | }
--------------------------------------------------------------------------------
/examples/testTag/testTagOnConstructorIgnoredInTestNamespace.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: calling from a class with a name ending Test
28 | }
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/examples/testTag/testTagOnMethodIgnoredInTestNamespace.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK - Called from Test namespace
28 | }
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/examples/package/packageRulesIgnoredForTestNamespace.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: calling from a test namespace
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/examples/friend/multipleFriends.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: FriendUpdater a friend of Person::updateName
22 | }
23 | }
24 |
25 | class AnotherFriendUpdater
26 | {
27 | public function update(Person $person): void
28 | {
29 | $person->updateName(); // OK: AnotherFriendUpdater a friend of Person::updateName
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/examples/injectableVersion/InjectableVersionOnExtendsThenImplements.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: calling from a class with a name ending Test
28 | }
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/examples/injectableVersion/InjectableVersionOnClass.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: calling from a test namespace
35 | }
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/examples/namespaceVisibility/namespaceVisibilityRulesIgnoredForTestNamespace.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: calling from a test namespace
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/examples/injectableVersion/MultipleLevelsOfInheritanceNoInjectableVersionOnClass.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK
20 | }
21 | }
22 |
23 | class Updater
24 | {
25 | public function updater(Person $person): void
26 | {
27 | $person->updateName(); // ERROR: Updater is not a Friend of Person
28 | }
29 | }
30 |
31 | $person = new Person();
32 | $person->updateName(); // ERROR
33 |
34 | class FriendUpdater
35 | {
36 | public function update(): void
37 | {
38 | $person = new Person();
39 | $person->updateName(); // OK
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/friend/friendOnStaticMethod.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK, call to Person::updateName from allowed namespace.
29 | }
30 | }
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/examples/injectableVersion/IterableInjectableVersion.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: Call to Person::updateName is in the allowed namespace.
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/examples/namespaceVisibility/namespaceVisibilityOnClassExcludeSubNamespaces.php:
--------------------------------------------------------------------------------
1 | updateName(); // ERROR: Call to Person::updateName in a sub namespace, where sub namespace is not allowed.
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.php-cs-fixer.php:
--------------------------------------------------------------------------------
1 | in(__DIR__ . '/src');
5 |
6 | $config = new PhpCsFixer\Config();
7 | return $config
8 | ->setRiskyAllowed(true)
9 | ->setRules(
10 | [
11 | '@PSR1' => true,
12 | '@PSR2' => true,
13 | '@PSR12' => true,
14 | '@Symfony' => true,
15 | '@Symfony:risky' => true,
16 | 'array_syntax' => ['syntax' => 'short'],
17 | 'no_useless_else' => true,
18 | 'no_useless_return' => true,
19 | 'ordered_imports' => true,
20 | 'phpdoc_order' => true,
21 | 'no_unused_imports' => true,
22 | 'strict_comparison' => true,
23 | 'phpdoc_align' => false,
24 | 'phpdoc_to_comment' => false,
25 | 'native_function_invocation' => false,
26 | ]
27 | )
28 | ->setFinder($finder)
29 | ;
30 |
--------------------------------------------------------------------------------
/examples/injectableVersion/MultipleLevelsOfInheritanceInjectableVersionOnInterface.php:
--------------------------------------------------------------------------------
1 | repository = $repository;
27 | }
28 | }
29 |
30 | class InjectingWrongVersion
31 | {
32 | public Repository $repository;
33 |
34 | #[CheckInjectableVersion]
35 | public function setRepository(DoctrineRepository $repository): void // ERROR
36 | {
37 | $this->repository = $repository;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/MustUseResult.php:
--------------------------------------------------------------------------------
1 | pence);
21 | * }
22 | * }
23 | * ```
24 | *
25 | * You might misuse the `add` method in this way:
26 | *
27 | * ```
28 | * $cost = new Money(5);
29 | * $cost->add(6); // ERROR - This statement has no effect.
30 | * ```
31 | *
32 | * But this would be OK:
33 | *
34 | * ```
35 | * $cost = new Money(5);
36 | * $updatedCost = $cost->add(6); // OK - The return from add method is being used.
37 | * ```
38 | */
39 | #[\Attribute(\Attribute::TARGET_METHOD)]
40 | final class MustUseResult
41 | {
42 | }
43 |
--------------------------------------------------------------------------------
/examples/namespaceVisibility/namespaceVisibilityOnMethodExcludeSubNamespace.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK
19 | }
20 | }
21 | }
22 |
23 |
24 |
25 | namespace NamespaceVisibilityOnMethodExluceSubNamespace\SubNamespace {
26 |
27 | use NamespaceVisibilityOnMethodExcludeSubNamespace\Person;
28 | class AnotherPersonUpdater
29 | {
30 | public function update(Person $person): void
31 | {
32 | $person->updateName(); // ERROR - Subnamespace of NamespaceVisibilityOnMethod, which is not allowed
33 | }
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/examples/friend/friendOnMethod.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: Method calls on same class is always allowed
19 | }
20 | }
21 |
22 | class Updater
23 | {
24 | public function updater(Person $person): void
25 | {
26 | $person->updateName(); // ERROR: Updater is not a friend of Person::updateName
27 | }
28 | }
29 |
30 | $person = new Person();
31 | $person->updateName(); // ERROR: Global namespace is not a friend of Person::updateName
32 |
33 | class FriendUpdater
34 | {
35 | public function update(): void
36 | {
37 | $person = new Person();
38 | $person->updateName(); // OK: FriendUpdater is a friend of Person::updateName
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/examples/package/packageOnConstructor.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK
19 | }
20 | }
21 |
22 | class Updater
23 | {
24 | public function updater(Person $person): void
25 | {
26 | $person->updateName(); // OK
27 | }
28 | }
29 |
30 | $person = new Person();
31 | $person->updateName(); // OK
32 | }
33 |
34 | namespace PackageOnMethod2 {
35 |
36 | use PackageOnMethod\Person;
37 |
38 | class AnotherUpdater
39 | {
40 | public function update(): void
41 | {
42 | $person = new Person();
43 | $person->updateName(); // ERROR: Call to Person::updateName which has package visibility
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/examples/override/overrideOnClass.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: Calls to same class allowed
20 | }
21 | }
22 |
23 | class Updater
24 | {
25 | public function updater(Person $person): void
26 | {
27 | $person->updateName(); // OK: Calls within same package allowed
28 | }
29 | }
30 |
31 | $person = new Person();
32 | $person->updateName(); // OK: Calls within same package allowed
33 |
34 | }
35 |
36 |
37 | namespace PackageOnClass2 {
38 |
39 | use PackageOnClass\Person;
40 |
41 | class AnotherUpdater
42 | {
43 | public function update(): void
44 | {
45 | $person = new Person();
46 | $person->updateName(); // ERROR: Call to Person::update method which has package visibility.
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/examples/namespaceVisibility/namespaceVisibilityOnConstructorExcludeSubNamespaces.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK
19 | }
20 | }
21 |
22 | class Updater
23 | {
24 | public function updater(Person $person): void
25 | {
26 | $person->updateName(); // OK
27 | }
28 | }
29 |
30 | $person = new Person();
31 | $person->updateName(); // OK
32 | }
33 |
34 |
35 |
36 | namespace NamespaceVisibilityOnMethod\SubNamespace {
37 |
38 | use NamespaceVisibilityOnMethod\Person;
39 | class AnotherPersonUpdater
40 | {
41 | public function update(Person $person): void
42 | {
43 | $person->updateName(); // OK - Subnamespace of NamespaceVisibilityOnMethod, which is allowed
44 | }
45 | }
46 | }
47 |
48 |
49 | namespace NamespaceVisibilityOnMethod2 {
50 |
51 | use NamespaceVisibilityOnMethod\Person;
52 |
53 | class AnotherUpdater
54 | {
55 | public function update(): void
56 | {
57 | $person = new Person();
58 | $person->updateName(); // ERROR: Call to Person::updateName which has namespaceVisibility visibility
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/examples/namespaceVisibility/namespaceVisibilityOnStaticMethod.php:
--------------------------------------------------------------------------------
1 | updateName(); // OK: Calls to same class allowed
20 | }
21 | }
22 |
23 | class Updater
24 | {
25 | public function updater(Person $person): void
26 | {
27 | $person->updateName(); // OK: Calls within same namespace allowed
28 | }
29 | }
30 |
31 | $person = new Person();
32 | $person->updateName(); // OK: Calls within same namespace allowed
33 |
34 | }
35 |
36 |
37 | namespace NamespaceVisibilityOnClass\SubNamesapce {
38 |
39 | use NamespaceVisibilityOnClass\Person;
40 |
41 | class AnotherClass
42 | {
43 | public function update(): void
44 | {
45 | $person = new Person();
46 | $person->updateName(); // OK: Calls within the same subnamespace allowed.
47 | }
48 | }
49 | }
50 |
51 |
52 | namespace NamespaceOnClass2 {
53 |
54 | use PackageOnClass\Person;
55 |
56 | class AnotherUpdater
57 | {
58 | public function update(): void
59 | {
60 | $person = new Person();
61 | $person->updateName(); // ERROR: Call to Person::update method which has namespace visibility.
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/.github/workflows/full-checks.yml:
--------------------------------------------------------------------------------
1 | name: "Full checks"
2 |
3 | on:
4 | schedule:
5 | - cron: '0 10 * * *'
6 | pull_request:
7 | push:
8 | branches:
9 | - main
10 |
11 | jobs:
12 | full-checks:
13 | name: "Full CI checks for all supported PHP versions"
14 |
15 | runs-on: ${{ matrix.operating-system }}
16 |
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | dependencies:
21 | - "locked"
22 | - "highest"
23 | php-version:
24 | - "8.0"
25 | - "8.1"
26 | - "8.2"
27 | - "8.3"
28 | - "8.4"
29 | - "8.5"
30 | operating-system:
31 | - "ubuntu-22.04"
32 |
33 | steps:
34 | - name: "Checkout"
35 | uses: "actions/checkout@v2"
36 |
37 | - name: "Install PHP"
38 | uses: "shivammathur/setup-php@v2"
39 | with:
40 | coverage: Xdebug
41 | php-version: "${{ matrix.php-version }}"
42 | tools: composer
43 |
44 | - name: Get composer cache directory
45 | id: composercache
46 | run: echo "::set-output name=dir::$(composer config cache-files-dir)"
47 |
48 | - name: Cache dependencies
49 | uses: actions/cache@v4
50 | with:
51 | path: ${{ steps.composercache.outputs.dir }}
52 | key: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }}"
53 | restore-keys: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}-${{ hashFiles('**/composer.lock') }}"
54 |
55 | - name: "Install locked dependencies"
56 | if: ${{ matrix.dependencies == 'locked' }}
57 | run: "composer install --no-interaction --no-progress"
58 |
59 | - name: "Install highest dependencies"
60 | if: ${{ matrix.dependencies == 'highest' }}
61 | run: "composer update --no-interaction --no-progress"
62 |
63 | - name: "Full CI"
64 | run: "composer ci"
65 |
--------------------------------------------------------------------------------
/examples/override/overrideRfcExamples.php:
--------------------------------------------------------------------------------
1 | `.
52 | E.g. the `#[friend]` attribute examples MUST be in the `examples/friend` directory.
53 |
54 | Each example file MUST be prefixed with the attribute name. E.g. `friendOnClass.php`.
55 | Each example MUST have a unique namespace. This is the name of the file, optionally with a number suffix.
56 | E.g. the file `friendOnClass` can have namespaces `FriendOnClass`, `FriendOnClass1`, `FriendOnClass2`, etc.
57 |
58 | If code in the example is showing an error that should be found by static analysis the line must end with `// ERROR `.
59 | See 5th line in code snippet below:
60 |
61 | ```php
62 | class Updater
63 | {
64 | public function updater(Person $person): void
65 | {
66 | $person->updateName(); // ERROR: Updater is not a Friend of Person
67 | }
68 | }
69 |
70 | ```
71 |
72 | To explicitly state where code is correct, add the following to the end of the line: `// OK `
73 | See 10th line in code snippet below:
74 |
75 | ```php
76 | class Person
77 | {
78 | #[Friend(FriendUpdater::class)]
79 | public function updateName(): void
80 | {
81 | }
82 |
83 | public function update(): void
84 | {
85 | $this->updateName(); // OK: Method calls on same class is always allowed
86 | }
87 | }
88 | ```
89 |
90 |
91 | ### Pre commit
92 |
93 | Prior to committing code please run the following:
94 |
95 | ```shell
96 | composer cs-fix # This fixes any coding style issues
97 | composer ci # This runs all the validation that is run by github actions.
98 | ```
99 |
100 | ### Updating static analysis plugins
101 |
102 | If your contribution has created or updated an Attribute or a file in [examples](examples) then the static analysis extensions/plugins will also need updating.
103 | The current known implementations are:
104 | - [PHPStan](https://github.com/DaveLiddament/phpstan-php-language-extension)
105 | - [Psalm](https://github.com/DaveLiddament/psalm-php-language-extension)
106 |
107 | If you have the relevant knowledge please make the updates to the appropriate repo. If you don't then please create an issue on the static analysis plugin's repo with details of that needs updating.
108 |
109 | Any updates to files in the [examples](examples) directory in this repository will need copying to the relevant static analysis's implementation repository in its `tests\data` directory.
110 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP Language Extensions (currently in BETA)
2 |
3 | [](https://packagist.org/packages/dave-liddament/php-language-extensions)
4 | [](https://packagist.org/packages/dave-liddament/php-language-extensions)
5 | [](https://github.com/DaveLiddament/php-language-extensions/blob/main/LICENSE.md)
6 | [](https://packagist.org/packages/dave-liddament/php-language-extensions/stats)
7 |
8 | [](https://github.com/DaveLiddament/php-language-extensions/actions)
9 | [](https://github.com/DaveLiddament/php-language-extensions/blob/main/psalm.xml)
10 | [](https://github.com/DaveLiddament/php-language-extensions/blob/main/phpstan.neon)
11 |
12 |
13 | This library provides [attributes](https://www.php.net/manual/en/language.attributes.overview.php) that are used by static analysers to enforce new language features.
14 | The intention, at least initially, is that these extra language features are enforced by static analysis tools (such as Psalm, PHPStan and, ideally, PhpStorm) and NOT at runtime.
15 |
16 | **Language feature added:**
17 | - [Friend](#friend)
18 | - [MustUseResult](#mustuseresult)
19 | - [NamespaceVisibility](#namespaceVisibility)
20 | - [InjectableVersion](#injectableVersion)
21 | - [Override](#override)
22 | - [RestrictTraitTo](#restricttraitto)
23 | - [Sealed](#sealed)
24 | - [TestTag](#testtag)
25 |
26 |
27 | ### Contents
28 |
29 | - [Installation](#installation)
30 | - [PHPStan](#phpstan)
31 | - [Psalm](#psalm)
32 | - [New Language Features](#new-language-features)
33 | - [Friend](#friend)
34 | - [MustUseResult](#mustuseresult)
35 | - [NamespaceVisibility](#namespaceVisibility)
36 | - [InjectableVersion](#injectableVersion)
37 | - [Override](#override)
38 | - [RestrictTraitTo](#restricttraitto)
39 | - [Sealed](#sealed)
40 | - [TestTag](#testtag)
41 | - Deprecated
42 | - [Package](#package) replace with [NamespaceVisibility](#namespaceVisibility)
43 |
44 | - [Further examples](#further-examples)
45 | - [Contributing](#contributing)
46 |
47 |
48 | ## Installation
49 |
50 | To make the attributes available for your codebase use:
51 |
52 | ```shell
53 | composer require dave-liddament/php-language-extensions
54 | ```
55 |
56 | NOTE: This only installs the attributes. A static analysis tool is used to enforce these language extensions.
57 | Use one of these:
58 |
59 | ### PHPStan
60 |
61 | If you're using PHPStan then use [this extension](https://github.com/DaveLiddament/phpstan-php-language-extensions) to enforce the rules.
62 |
63 | ```shell
64 | composer require --dev dave-liddament/phpstan-php-language-extensions
65 | ```
66 |
67 | ### Psalm
68 |
69 | Coming soon.
70 |
71 |
72 |
73 |
74 | ## New language features
75 |
76 | ## Friend
77 |
78 | A method or class can supply via a `#[Friend]` attribute a list of classes. Only these classes can call the method.
79 | This is loosely based on the C++ friend feature.
80 |
81 | In the example below the `Person::__construct` method can only be called from `PersonBuilder`:
82 |
83 | ```php
84 |
85 | class Person
86 | {
87 | #[Friend(PersonBuilder::class)]
88 | public function __construct()
89 | {
90 | // Some implementation
91 | }
92 | }
93 |
94 |
95 | class PersonBuilder
96 | {
97 | public function build(): Person
98 | {
99 | $person = new Person(): // OK as PersonBuilder is allowed to call Person's construct method.
100 | // set up Person
101 | return $person;
102 | }
103 | }
104 |
105 |
106 | // ERROR Call to Person::__construct is not from PersonBuilder
107 | $person = new Person();
108 |
109 | ```
110 |
111 | **NOTES:**
112 | - Multiple classes can be specified. E.g. `#[Friend(Foo::class, Bar::class)]`
113 | - A class can have a `#[Friend]` attribute, classes listed here are applied to every method.
114 | ```php
115 | #[Friend(Foo::class)]
116 | class Entity
117 | {
118 | public function ping(): void // ping has friend Foo
119 | {
120 | }
121 | }
122 | ```
123 | - The `#[Friend]` attribute is additive. If a class and a method have the `#[Friend]` the method can be called from any of the classes listed. E.g.
124 | ```php
125 | #[Friend(Foo::class)]
126 | class Entity
127 | {
128 | #[Friend(Bar::class)]
129 | public function pong(): void // pong has friends Foo and Bar
130 | {
131 | }
132 | }
133 | ```
134 | - This is currently limited to method calls (including `__construct`).
135 |
136 | ## MustUseResult
137 |
138 | A `#[MustUseResult]` attribute can be used on methods. This enforces the result from the method call must be used.
139 |
140 | E.g. if you have a class like this:
141 |
142 | ```php
143 |
144 | class Money {
145 |
146 | public function __construct(public readonly int $pence)
147 | {}
148 |
149 | #[MustUseResult]
150 | public function add(int $pence): self
151 | {
152 | return new self($pence + $this->pence);
153 | }
154 | }
155 | ```
156 |
157 | You might misuse the `add` method in this way:
158 |
159 | ```php
160 | $cost = new Money(5);
161 | $cost->add(6); // ERROR - The call to the add method has no effect.
162 | ```
163 |
164 | But this would be OK:
165 |
166 | ```php
167 | $cost = new Money(5);
168 | $updatedCost = $cost->add(6); // OK - The return from add method is being used.
169 | ```
170 |
171 | ## NamespaceVisibility
172 |
173 | The `#[NamespaceVisibility]` attribute acts as extra visibility modifier like `public`, `protected` and `private`.
174 | By default, the `#[NamespaceVisibility]` attribute limits the visibility of a class or method to only being accessible from in the same namespace, or sub namespace.
175 |
176 | Example applying `#[NamespaceVisibility]` to the `Telephone::ring` method:
177 |
178 | ```php
179 | namespace Foo {
180 |
181 | class Telephone
182 | {
183 | #[NamespaceVisibility]
184 | public function ring(): void
185 | {
186 | }
187 | }
188 |
189 | class Ringer
190 | {
191 | public function ring(Telephone $telephone): Person
192 | {
193 | $telephone->ring(); // OK calling Telephone::ring() from same namespace
194 | }
195 | }
196 | }
197 |
198 | namespace Foo\SubNamespace {
199 |
200 | use Foo\Telephone;
201 |
202 | class SubNamespaceRinger
203 | {
204 | public function ring(Telephone $telephone): Person
205 | {
206 | $telephone->ring(); // OK calling Telephone::ring() from sub namespace
207 | }
208 | }
209 | }
210 |
211 |
212 | namespace Bar {
213 |
214 | use Foo\Telephone;
215 |
216 | class DifferentNamespaceRinger
217 | {
218 | public function ring(Telephone $telephone): Person
219 | {
220 | $telephone->ring(); // ERROR calling Telephone::ring() from different namespace
221 | }
222 | }
223 | }
224 | ```
225 |
226 | The `#[NamespaceVisibility]` attribute has 2 optional arguments:
227 |
228 | #### excludeSubNamespaces option
229 |
230 | This is a boolean value. Its default value is false.
231 | If set to true then calls to methods from sub namespaces are not allowed.
232 | E.g.
233 |
234 | ```php
235 | namespace Foo {
236 |
237 | class Telephone
238 | {
239 | #[NamespaceVisibility(excludeSubNamespaces: true)]
240 | public function ring(): void
241 | {
242 | }
243 | }
244 |
245 | }
246 |
247 | namespace Foo\SubNamespace {
248 |
249 | use Foo\Telephone;
250 |
251 | class SubNamespaceRinger
252 | {
253 | public function ring(Telephone $telephone): Person
254 | {
255 | $telephone->ring(); // ERROR - Not allowed to call Telephone::ring() from a sub namespace
256 | }
257 | }
258 | }
259 | ```
260 |
261 | #### namespace option
262 |
263 | This is a string or null value. Its default value is null.
264 | If it is set, then this is the namespace that you are allowed to call the method on.
265 |
266 | In the example below you can only call `Telephone::ring` from the `Bar` namespace.
267 |
268 |
269 | ```php
270 | namespace Foo {
271 |
272 | class Telephone
273 | {
274 | #[NamespaceVisibility(namespace: "Bar")]
275 | public function ring(): void
276 | {
277 | }
278 | }
279 |
280 | class Ringer
281 | {
282 | public function ring(Telephone $telephone): void
283 | {
284 | $telephone->ring(); // ERROR - Can only all Telephone::ring() from namespace Bar
285 | }
286 | }
287 | }
288 |
289 | namespace Bar {
290 |
291 | use Foo\Telephone;
292 |
293 | class AnotherRinger
294 | {
295 | public function ring(Telephone $telephone): void
296 | {
297 | $telephone->ring(); // OK - Allowed to call Telephone::ring() from namespace Bar
298 | }
299 | }
300 | }
301 | ```
302 |
303 | #### NamespaceVisibility on classes
304 |
305 | If a class was the `#[NamespaceVisibility]` Attribute, then all its public methods are treated as Namespace visibility.
306 |
307 | E.g.
308 |
309 | ```php
310 | namespace Foo {
311 |
312 | #[NamespaceVisibility()]
313 | class Telephone
314 | {
315 | public function ring(): void // This method has NamespaceVisibility
316 | { }
317 | }
318 | }
319 | ```
320 |
321 | If both the class and one of the class's methods has a `#[NamespaceVisibility]` attribute, then the method's attribute
322 | takes precedence.
323 |
324 | ```php
325 | namespace Foo {
326 |
327 | #[NamespaceVisibility(namespace: 'Bar')]
328 | class Telephone
329 | {
330 | #[NamespaceVisibility(namespace: 'Baz')]
331 | public function ring(): void // This method can only be called from the namespace Baz
332 | { }
333 | }
334 | }
335 | ```
336 |
337 |
338 | #### NOTES:
339 |
340 | - If adding the `#[NamespaceVisibility]` to a method, this method MUST have public visibility.
341 | - This is currently limited to method calls (including `__construct`).
342 |
343 |
344 |
345 | ## InjectableVersion
346 |
347 | The `#[InjectableVersion]` is used in conjunction with dependency injection.
348 | `#[InjectableVersion]` is applied to a class or interface.
349 | It denotes that it is this version and not any classes that implement/extend that should be used in the codebase.
350 |
351 | E.g.
352 |
353 | ```php
354 |
355 | #[InjectableVersion]
356 | class PersonRepository {...} // This is the version that should be type hinted in constructors.
357 |
358 | class DoctrinePersonRepository extends PersonRepository {...}
359 |
360 | class PersonCreator {
361 | public function __construct(
362 | private PersonRepository $personRepository, // OK - using the injectable version
363 | )
364 | }
365 | class PersonUpdater {
366 | public function __construct(
367 | private DoctrinePersonRepository $personRepository, // ERROR - not using the InjectableVersion
368 | )
369 | }
370 | ```
371 |
372 | This also works for collections:
373 |
374 | ```php
375 |
376 | #[InjectableVersion]
377 | interface Validator {...} // This is the version that should be type hinted in constructors.
378 |
379 | class NameValidator implements Validator {...}
380 | class AddressValidator implements Validator {...}
381 |
382 | class PersonValidator {
383 | /** @param Validator[] $validators */
384 | public function __construct(
385 | private array $validators, // OK - using the injectable version
386 | )
387 | }
388 | ```
389 |
390 | By default, only constructor arguments are checked. Most DI should be done via constructor injection.
391 |
392 | In cases where dependencies are injected by methods that aren't constructors, the method must be marked with a `#[CheckInjectableVersion]`:
393 |
394 | ```php
395 |
396 | #[InjectableVersion]
397 | interface Logger {...}
398 |
399 | class FileLogger implements Logger {...}
400 |
401 | class MyService
402 | {
403 | #[CheckInjectableVersion]
404 | public function setLogger(Logger $logger): void {} // OK - Injectable Version injected
405 |
406 | public function addLogger(FileLogger $logger): void {} // No issue raised because addLogger doesn't have the #[CheckInjectableVersion] attribute.
407 | }
408 |
409 | ```
410 |
411 | ## Override
412 |
413 | The `#[Override]` attribute is used to denote that a method is overriding a method in a parent class. This is the functionality is similar to the `@override` annotation in Java.
414 |
415 | This is temporary until PHP 8.3 is released. See the [RFC](https://wiki.php.net/rfc/marking_overriden_methods) that will be implemented in PHP 8.3.
416 |
417 | NOTE:
418 |
419 | - If you are using PHP 8.3 then use the real `#[Override]` attribute.
420 | - This implementation doesn't consider traits.
421 |
422 | ## RestrictTraitTo
423 |
424 | This limits the use of a Trait to only be used by a specified class of a child of that class.
425 |
426 | E.g. this trait is limited to classes that are or extend `Controller`
427 |
428 | ```php
429 | #[RestrictTraitTo(Controller::class)]
430 | trait ControllerHelpers {}
431 | ```
432 |
433 | This would be allowed:
434 | ```php
435 | class LoginController extends Controller {
436 | use ControllerHelpers;
437 | }
438 | ```
439 |
440 | But this would NOT be allowed:
441 | ```php
442 | class Repository {
443 | use ControllerHelpers;
444 | }
445 | ```
446 |
447 |
448 | ## Sealed
449 |
450 | This is inspired by the rejected [sealed classes RFC](https://wiki.php.net/rfc/sealed_classes)
451 |
452 | The `#[Sealed]` attribute takes a list of classes or interfaces that can extend/implement the class/interface.
453 |
454 | E.g.
455 |
456 | ```php
457 |
458 | #[Sealed([Success::class, Failure::class])]
459 | abstract class Result {} // Result can only be extended by Success or Failure
460 |
461 | // OK
462 | class Success extends Result {}
463 |
464 | // OK
465 | class Failure extends Result {}
466 |
467 | // ERROR AnotherClass is not allowed to extend Result
468 | class AnotherClass extends Result {}
469 | ```
470 |
471 |
472 | ## TestTag
473 |
474 | The `#[TestTag]` attribute is an idea borrowed from hardware testing. Classes or methods marked with this attribute are only available to test code.
475 |
476 | E.g.
477 |
478 | ```php
479 | class Person {
480 |
481 | #[TestTag]
482 | public function setId(int $id)
483 | {
484 | $this->id = $id;
485 | }
486 | }
487 |
488 |
489 | function updatePersonId(Person $person): void
490 | {
491 | $person->setId(10); // ERROR - not test code.
492 | }
493 |
494 |
495 | class PersonTest
496 | {
497 | public function setup(): void
498 | {
499 | $person = new Person();
500 | $person->setId(10); // OK - This is test code.
501 | }
502 | }
503 | ```
504 |
505 | NOTES:
506 | - Classes with the `#[TestTag]` will have an error when any interaction with the class is done.
507 | - Methods with the `#[TestTag]` MUST have public visibility.
508 | - For determining what is "test code" see the relevant plugin. E.g. the [PHPStan extension](https://github.com/DaveLiddament/phpstan-php-language-extensions) can be setup to either:
509 | - Assume all classes that end `Test` is test code. See [className config option](https://github.com/DaveLiddament/phpstan-php-language-extensions#exclude-checks-on-class-names-ending-with-test).
510 | - Assume all classes within a given namespace is test code. See [namespace config option](https://github.com/DaveLiddament/phpstan-php-language-extensions#exclude-checks-based-on-test-namespace).
511 |
512 |
513 | ## Deprecated Attributes
514 |
515 | ### Package (deprecated)
516 |
517 | The `#[Package]` attribute acts like an extra visibility modifier like `public`, `protected` and `private`. It is inspired by Java's `package` visibility modifier.
518 | The `#[Package]` attribute limits the visibility of a class or method to only being accessible from code in the same namespace.
519 |
520 | This has been replaced by the `#[NamespaceVisibility]` attribute. To upgrade replace:
521 |
522 | `#[Package]` with `#[NamespaceVisibility(excludeSubNamespaces=true)]`
523 |
524 |
525 | **NOTES:**
526 |
527 | - If adding the `#[Package]` to a method, this method MUST have public visibility.
528 | - If a class is marked with `#[Package]` then all its public methods are treated as having package visibility.
529 | - This is currently limited to method calls (including `__construct`).
530 | - Namespaces must match exactly. E.g. a package level method in `Foo\Bar` is only accessible from `Foo\Bar`. It is not accessible from `Foo` or `Foo\Bar\Baz`
531 |
532 |
533 |
534 |
535 | ## Further examples
536 |
537 | More detailed examples of how to use attributes is found in [examples](examples/).
538 |
539 |
540 | ## Contributing
541 |
542 | See [Contributing](CONTRIBUTING.md).
543 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "eafc029cb42c297b53caada885dfcca3",
8 | "packages": [],
9 | "packages-dev": [
10 | {
11 | "name": "composer/pcre",
12 | "version": "3.1.0",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/composer/pcre.git",
16 | "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2",
21 | "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2",
22 | "shasum": ""
23 | },
24 | "require": {
25 | "php": "^7.4 || ^8.0"
26 | },
27 | "require-dev": {
28 | "phpstan/phpstan": "^1.3",
29 | "phpstan/phpstan-strict-rules": "^1.1",
30 | "symfony/phpunit-bridge": "^5"
31 | },
32 | "type": "library",
33 | "extra": {
34 | "branch-alias": {
35 | "dev-main": "3.x-dev"
36 | }
37 | },
38 | "autoload": {
39 | "psr-4": {
40 | "Composer\\Pcre\\": "src"
41 | }
42 | },
43 | "notification-url": "https://packagist.org/downloads/",
44 | "license": [
45 | "MIT"
46 | ],
47 | "authors": [
48 | {
49 | "name": "Jordi Boggiano",
50 | "email": "j.boggiano@seld.be",
51 | "homepage": "http://seld.be"
52 | }
53 | ],
54 | "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
55 | "keywords": [
56 | "PCRE",
57 | "preg",
58 | "regex",
59 | "regular expression"
60 | ],
61 | "support": {
62 | "issues": "https://github.com/composer/pcre/issues",
63 | "source": "https://github.com/composer/pcre/tree/3.1.0"
64 | },
65 | "funding": [
66 | {
67 | "url": "https://packagist.com",
68 | "type": "custom"
69 | },
70 | {
71 | "url": "https://github.com/composer",
72 | "type": "github"
73 | },
74 | {
75 | "url": "https://tidelift.com/funding/github/packagist/composer/composer",
76 | "type": "tidelift"
77 | }
78 | ],
79 | "time": "2022-11-17T09:50:14+00:00"
80 | },
81 | {
82 | "name": "composer/semver",
83 | "version": "3.3.2",
84 | "source": {
85 | "type": "git",
86 | "url": "https://github.com/composer/semver.git",
87 | "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
88 | },
89 | "dist": {
90 | "type": "zip",
91 | "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
92 | "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
93 | "shasum": ""
94 | },
95 | "require": {
96 | "php": "^5.3.2 || ^7.0 || ^8.0"
97 | },
98 | "require-dev": {
99 | "phpstan/phpstan": "^1.4",
100 | "symfony/phpunit-bridge": "^4.2 || ^5"
101 | },
102 | "type": "library",
103 | "extra": {
104 | "branch-alias": {
105 | "dev-main": "3.x-dev"
106 | }
107 | },
108 | "autoload": {
109 | "psr-4": {
110 | "Composer\\Semver\\": "src"
111 | }
112 | },
113 | "notification-url": "https://packagist.org/downloads/",
114 | "license": [
115 | "MIT"
116 | ],
117 | "authors": [
118 | {
119 | "name": "Nils Adermann",
120 | "email": "naderman@naderman.de",
121 | "homepage": "http://www.naderman.de"
122 | },
123 | {
124 | "name": "Jordi Boggiano",
125 | "email": "j.boggiano@seld.be",
126 | "homepage": "http://seld.be"
127 | },
128 | {
129 | "name": "Rob Bast",
130 | "email": "rob.bast@gmail.com",
131 | "homepage": "http://robbast.nl"
132 | }
133 | ],
134 | "description": "Semver library that offers utilities, version constraint parsing and validation.",
135 | "keywords": [
136 | "semantic",
137 | "semver",
138 | "validation",
139 | "versioning"
140 | ],
141 | "support": {
142 | "irc": "irc://irc.freenode.org/composer",
143 | "issues": "https://github.com/composer/semver/issues",
144 | "source": "https://github.com/composer/semver/tree/3.3.2"
145 | },
146 | "funding": [
147 | {
148 | "url": "https://packagist.com",
149 | "type": "custom"
150 | },
151 | {
152 | "url": "https://github.com/composer",
153 | "type": "github"
154 | },
155 | {
156 | "url": "https://tidelift.com/funding/github/packagist/composer/composer",
157 | "type": "tidelift"
158 | }
159 | ],
160 | "time": "2022-04-01T19:23:25+00:00"
161 | },
162 | {
163 | "name": "composer/xdebug-handler",
164 | "version": "3.0.3",
165 | "source": {
166 | "type": "git",
167 | "url": "https://github.com/composer/xdebug-handler.git",
168 | "reference": "ced299686f41dce890debac69273b47ffe98a40c"
169 | },
170 | "dist": {
171 | "type": "zip",
172 | "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c",
173 | "reference": "ced299686f41dce890debac69273b47ffe98a40c",
174 | "shasum": ""
175 | },
176 | "require": {
177 | "composer/pcre": "^1 || ^2 || ^3",
178 | "php": "^7.2.5 || ^8.0",
179 | "psr/log": "^1 || ^2 || ^3"
180 | },
181 | "require-dev": {
182 | "phpstan/phpstan": "^1.0",
183 | "phpstan/phpstan-strict-rules": "^1.1",
184 | "symfony/phpunit-bridge": "^6.0"
185 | },
186 | "type": "library",
187 | "autoload": {
188 | "psr-4": {
189 | "Composer\\XdebugHandler\\": "src"
190 | }
191 | },
192 | "notification-url": "https://packagist.org/downloads/",
193 | "license": [
194 | "MIT"
195 | ],
196 | "authors": [
197 | {
198 | "name": "John Stevenson",
199 | "email": "john-stevenson@blueyonder.co.uk"
200 | }
201 | ],
202 | "description": "Restarts a process without Xdebug.",
203 | "keywords": [
204 | "Xdebug",
205 | "performance"
206 | ],
207 | "support": {
208 | "irc": "irc://irc.freenode.org/composer",
209 | "issues": "https://github.com/composer/xdebug-handler/issues",
210 | "source": "https://github.com/composer/xdebug-handler/tree/3.0.3"
211 | },
212 | "funding": [
213 | {
214 | "url": "https://packagist.com",
215 | "type": "custom"
216 | },
217 | {
218 | "url": "https://github.com/composer",
219 | "type": "github"
220 | },
221 | {
222 | "url": "https://tidelift.com/funding/github/packagist/composer/composer",
223 | "type": "tidelift"
224 | }
225 | ],
226 | "time": "2022-02-25T21:32:43+00:00"
227 | },
228 | {
229 | "name": "doctrine/annotations",
230 | "version": "1.14.2",
231 | "source": {
232 | "type": "git",
233 | "url": "https://github.com/doctrine/annotations.git",
234 | "reference": "ad785217c1e9555a7d6c6c8c9f406395a5e2882b"
235 | },
236 | "dist": {
237 | "type": "zip",
238 | "url": "https://api.github.com/repos/doctrine/annotations/zipball/ad785217c1e9555a7d6c6c8c9f406395a5e2882b",
239 | "reference": "ad785217c1e9555a7d6c6c8c9f406395a5e2882b",
240 | "shasum": ""
241 | },
242 | "require": {
243 | "doctrine/lexer": "^1 || ^2",
244 | "ext-tokenizer": "*",
245 | "php": "^7.1 || ^8.0",
246 | "psr/cache": "^1 || ^2 || ^3"
247 | },
248 | "require-dev": {
249 | "doctrine/cache": "^1.11 || ^2.0",
250 | "doctrine/coding-standard": "^9 || ^10",
251 | "phpstan/phpstan": "~1.4.10 || ^1.8.0",
252 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
253 | "symfony/cache": "^4.4 || ^5.4 || ^6",
254 | "vimeo/psalm": "^4.10"
255 | },
256 | "suggest": {
257 | "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
258 | },
259 | "type": "library",
260 | "autoload": {
261 | "psr-4": {
262 | "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
263 | }
264 | },
265 | "notification-url": "https://packagist.org/downloads/",
266 | "license": [
267 | "MIT"
268 | ],
269 | "authors": [
270 | {
271 | "name": "Guilherme Blanco",
272 | "email": "guilhermeblanco@gmail.com"
273 | },
274 | {
275 | "name": "Roman Borschel",
276 | "email": "roman@code-factory.org"
277 | },
278 | {
279 | "name": "Benjamin Eberlei",
280 | "email": "kontakt@beberlei.de"
281 | },
282 | {
283 | "name": "Jonathan Wage",
284 | "email": "jonwage@gmail.com"
285 | },
286 | {
287 | "name": "Johannes Schmitt",
288 | "email": "schmittjoh@gmail.com"
289 | }
290 | ],
291 | "description": "Docblock Annotations Parser",
292 | "homepage": "https://www.doctrine-project.org/projects/annotations.html",
293 | "keywords": [
294 | "annotations",
295 | "docblock",
296 | "parser"
297 | ],
298 | "support": {
299 | "issues": "https://github.com/doctrine/annotations/issues",
300 | "source": "https://github.com/doctrine/annotations/tree/1.14.2"
301 | },
302 | "time": "2022-12-15T06:48:22+00:00"
303 | },
304 | {
305 | "name": "doctrine/deprecations",
306 | "version": "v1.0.0",
307 | "source": {
308 | "type": "git",
309 | "url": "https://github.com/doctrine/deprecations.git",
310 | "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
311 | },
312 | "dist": {
313 | "type": "zip",
314 | "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
315 | "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
316 | "shasum": ""
317 | },
318 | "require": {
319 | "php": "^7.1|^8.0"
320 | },
321 | "require-dev": {
322 | "doctrine/coding-standard": "^9",
323 | "phpunit/phpunit": "^7.5|^8.5|^9.5",
324 | "psr/log": "^1|^2|^3"
325 | },
326 | "suggest": {
327 | "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
328 | },
329 | "type": "library",
330 | "autoload": {
331 | "psr-4": {
332 | "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
333 | }
334 | },
335 | "notification-url": "https://packagist.org/downloads/",
336 | "license": [
337 | "MIT"
338 | ],
339 | "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
340 | "homepage": "https://www.doctrine-project.org/",
341 | "support": {
342 | "issues": "https://github.com/doctrine/deprecations/issues",
343 | "source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
344 | },
345 | "time": "2022-05-02T15:47:09+00:00"
346 | },
347 | {
348 | "name": "doctrine/lexer",
349 | "version": "2.1.0",
350 | "source": {
351 | "type": "git",
352 | "url": "https://github.com/doctrine/lexer.git",
353 | "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124"
354 | },
355 | "dist": {
356 | "type": "zip",
357 | "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124",
358 | "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124",
359 | "shasum": ""
360 | },
361 | "require": {
362 | "doctrine/deprecations": "^1.0",
363 | "php": "^7.1 || ^8.0"
364 | },
365 | "require-dev": {
366 | "doctrine/coding-standard": "^9 || ^10",
367 | "phpstan/phpstan": "^1.3",
368 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
369 | "psalm/plugin-phpunit": "^0.18.3",
370 | "vimeo/psalm": "^4.11 || ^5.0"
371 | },
372 | "type": "library",
373 | "autoload": {
374 | "psr-4": {
375 | "Doctrine\\Common\\Lexer\\": "src"
376 | }
377 | },
378 | "notification-url": "https://packagist.org/downloads/",
379 | "license": [
380 | "MIT"
381 | ],
382 | "authors": [
383 | {
384 | "name": "Guilherme Blanco",
385 | "email": "guilhermeblanco@gmail.com"
386 | },
387 | {
388 | "name": "Roman Borschel",
389 | "email": "roman@code-factory.org"
390 | },
391 | {
392 | "name": "Johannes Schmitt",
393 | "email": "schmittjoh@gmail.com"
394 | }
395 | ],
396 | "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
397 | "homepage": "https://www.doctrine-project.org/projects/lexer.html",
398 | "keywords": [
399 | "annotations",
400 | "docblock",
401 | "lexer",
402 | "parser",
403 | "php"
404 | ],
405 | "support": {
406 | "issues": "https://github.com/doctrine/lexer/issues",
407 | "source": "https://github.com/doctrine/lexer/tree/2.1.0"
408 | },
409 | "funding": [
410 | {
411 | "url": "https://www.doctrine-project.org/sponsorship.html",
412 | "type": "custom"
413 | },
414 | {
415 | "url": "https://www.patreon.com/phpdoctrine",
416 | "type": "patreon"
417 | },
418 | {
419 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
420 | "type": "tidelift"
421 | }
422 | ],
423 | "time": "2022-12-14T08:49:07+00:00"
424 | },
425 | {
426 | "name": "friendsofphp/php-cs-fixer",
427 | "version": "v3.13.2",
428 | "source": {
429 | "type": "git",
430 | "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
431 | "reference": "3952f08a81bd3b1b15e11c3de0b6bf037faa8496"
432 | },
433 | "dist": {
434 | "type": "zip",
435 | "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/3952f08a81bd3b1b15e11c3de0b6bf037faa8496",
436 | "reference": "3952f08a81bd3b1b15e11c3de0b6bf037faa8496",
437 | "shasum": ""
438 | },
439 | "require": {
440 | "composer/semver": "^3.2",
441 | "composer/xdebug-handler": "^3.0.3",
442 | "doctrine/annotations": "^1.13",
443 | "ext-json": "*",
444 | "ext-tokenizer": "*",
445 | "php": "^7.4 || ^8.0",
446 | "sebastian/diff": "^4.0",
447 | "symfony/console": "^5.4 || ^6.0",
448 | "symfony/event-dispatcher": "^5.4 || ^6.0",
449 | "symfony/filesystem": "^5.4 || ^6.0",
450 | "symfony/finder": "^5.4 || ^6.0",
451 | "symfony/options-resolver": "^5.4 || ^6.0",
452 | "symfony/polyfill-mbstring": "^1.23",
453 | "symfony/polyfill-php80": "^1.25",
454 | "symfony/polyfill-php81": "^1.25",
455 | "symfony/process": "^5.4 || ^6.0",
456 | "symfony/stopwatch": "^5.4 || ^6.0"
457 | },
458 | "require-dev": {
459 | "justinrainbow/json-schema": "^5.2",
460 | "keradus/cli-executor": "^2.0",
461 | "mikey179/vfsstream": "^1.6.10",
462 | "php-coveralls/php-coveralls": "^2.5.2",
463 | "php-cs-fixer/accessible-object": "^1.1",
464 | "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2",
465 | "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1",
466 | "phpspec/prophecy": "^1.15",
467 | "phpspec/prophecy-phpunit": "^2.0",
468 | "phpunit/phpunit": "^9.5",
469 | "phpunitgoodpractices/polyfill": "^1.6",
470 | "phpunitgoodpractices/traits": "^1.9.2",
471 | "symfony/phpunit-bridge": "^6.0",
472 | "symfony/yaml": "^5.4 || ^6.0"
473 | },
474 | "suggest": {
475 | "ext-dom": "For handling output formats in XML",
476 | "ext-mbstring": "For handling non-UTF8 characters."
477 | },
478 | "bin": [
479 | "php-cs-fixer"
480 | ],
481 | "type": "application",
482 | "autoload": {
483 | "psr-4": {
484 | "PhpCsFixer\\": "src/"
485 | }
486 | },
487 | "notification-url": "https://packagist.org/downloads/",
488 | "license": [
489 | "MIT"
490 | ],
491 | "authors": [
492 | {
493 | "name": "Fabien Potencier",
494 | "email": "fabien@symfony.com"
495 | },
496 | {
497 | "name": "Dariusz Rumiński",
498 | "email": "dariusz.ruminski@gmail.com"
499 | }
500 | ],
501 | "description": "A tool to automatically fix PHP code style",
502 | "support": {
503 | "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
504 | "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.13.2"
505 | },
506 | "funding": [
507 | {
508 | "url": "https://github.com/keradus",
509 | "type": "github"
510 | }
511 | ],
512 | "time": "2023-01-02T23:53:50+00:00"
513 | },
514 | {
515 | "name": "php-parallel-lint/php-parallel-lint",
516 | "version": "v1.3.2",
517 | "source": {
518 | "type": "git",
519 | "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git",
520 | "reference": "6483c9832e71973ed29cf71bd6b3f4fde438a9de"
521 | },
522 | "dist": {
523 | "type": "zip",
524 | "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6483c9832e71973ed29cf71bd6b3f4fde438a9de",
525 | "reference": "6483c9832e71973ed29cf71bd6b3f4fde438a9de",
526 | "shasum": ""
527 | },
528 | "require": {
529 | "ext-json": "*",
530 | "php": ">=5.3.0"
531 | },
532 | "replace": {
533 | "grogy/php-parallel-lint": "*",
534 | "jakub-onderka/php-parallel-lint": "*"
535 | },
536 | "require-dev": {
537 | "nette/tester": "^1.3 || ^2.0",
538 | "php-parallel-lint/php-console-highlighter": "0.* || ^1.0",
539 | "squizlabs/php_codesniffer": "^3.6"
540 | },
541 | "suggest": {
542 | "php-parallel-lint/php-console-highlighter": "Highlight syntax in code snippet"
543 | },
544 | "bin": [
545 | "parallel-lint"
546 | ],
547 | "type": "library",
548 | "autoload": {
549 | "classmap": [
550 | "./src/"
551 | ]
552 | },
553 | "notification-url": "https://packagist.org/downloads/",
554 | "license": [
555 | "BSD-2-Clause"
556 | ],
557 | "authors": [
558 | {
559 | "name": "Jakub Onderka",
560 | "email": "ahoj@jakubonderka.cz"
561 | }
562 | ],
563 | "description": "This tool check syntax of PHP files about 20x faster than serial check.",
564 | "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint",
565 | "support": {
566 | "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues",
567 | "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.3.2"
568 | },
569 | "time": "2022-02-21T12:50:22+00:00"
570 | },
571 | {
572 | "name": "phpstan/phpstan",
573 | "version": "1.12.6",
574 | "source": {
575 | "type": "git",
576 | "url": "https://github.com/phpstan/phpstan.git",
577 | "reference": "dc4d2f145a88ea7141ae698effd64d9df46527ae"
578 | },
579 | "dist": {
580 | "type": "zip",
581 | "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dc4d2f145a88ea7141ae698effd64d9df46527ae",
582 | "reference": "dc4d2f145a88ea7141ae698effd64d9df46527ae",
583 | "shasum": ""
584 | },
585 | "require": {
586 | "php": "^7.2|^8.0"
587 | },
588 | "conflict": {
589 | "phpstan/phpstan-shim": "*"
590 | },
591 | "bin": [
592 | "phpstan",
593 | "phpstan.phar"
594 | ],
595 | "type": "library",
596 | "autoload": {
597 | "files": [
598 | "bootstrap.php"
599 | ]
600 | },
601 | "notification-url": "https://packagist.org/downloads/",
602 | "license": [
603 | "MIT"
604 | ],
605 | "description": "PHPStan - PHP Static Analysis Tool",
606 | "keywords": [
607 | "dev",
608 | "static analysis"
609 | ],
610 | "support": {
611 | "docs": "https://phpstan.org/user-guide/getting-started",
612 | "forum": "https://github.com/phpstan/phpstan/discussions",
613 | "issues": "https://github.com/phpstan/phpstan/issues",
614 | "security": "https://github.com/phpstan/phpstan/security/policy",
615 | "source": "https://github.com/phpstan/phpstan-src"
616 | },
617 | "funding": [
618 | {
619 | "url": "https://github.com/ondrejmirtes",
620 | "type": "github"
621 | },
622 | {
623 | "url": "https://github.com/phpstan",
624 | "type": "github"
625 | }
626 | ],
627 | "time": "2024-10-06T15:03:59+00:00"
628 | },
629 | {
630 | "name": "psr/cache",
631 | "version": "3.0.0",
632 | "source": {
633 | "type": "git",
634 | "url": "https://github.com/php-fig/cache.git",
635 | "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
636 | },
637 | "dist": {
638 | "type": "zip",
639 | "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
640 | "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
641 | "shasum": ""
642 | },
643 | "require": {
644 | "php": ">=8.0.0"
645 | },
646 | "type": "library",
647 | "extra": {
648 | "branch-alias": {
649 | "dev-master": "1.0.x-dev"
650 | }
651 | },
652 | "autoload": {
653 | "psr-4": {
654 | "Psr\\Cache\\": "src/"
655 | }
656 | },
657 | "notification-url": "https://packagist.org/downloads/",
658 | "license": [
659 | "MIT"
660 | ],
661 | "authors": [
662 | {
663 | "name": "PHP-FIG",
664 | "homepage": "https://www.php-fig.org/"
665 | }
666 | ],
667 | "description": "Common interface for caching libraries",
668 | "keywords": [
669 | "cache",
670 | "psr",
671 | "psr-6"
672 | ],
673 | "support": {
674 | "source": "https://github.com/php-fig/cache/tree/3.0.0"
675 | },
676 | "time": "2021-02-03T23:26:27+00:00"
677 | },
678 | {
679 | "name": "psr/container",
680 | "version": "2.0.2",
681 | "source": {
682 | "type": "git",
683 | "url": "https://github.com/php-fig/container.git",
684 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
685 | },
686 | "dist": {
687 | "type": "zip",
688 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
689 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
690 | "shasum": ""
691 | },
692 | "require": {
693 | "php": ">=7.4.0"
694 | },
695 | "type": "library",
696 | "extra": {
697 | "branch-alias": {
698 | "dev-master": "2.0.x-dev"
699 | }
700 | },
701 | "autoload": {
702 | "psr-4": {
703 | "Psr\\Container\\": "src/"
704 | }
705 | },
706 | "notification-url": "https://packagist.org/downloads/",
707 | "license": [
708 | "MIT"
709 | ],
710 | "authors": [
711 | {
712 | "name": "PHP-FIG",
713 | "homepage": "https://www.php-fig.org/"
714 | }
715 | ],
716 | "description": "Common Container Interface (PHP FIG PSR-11)",
717 | "homepage": "https://github.com/php-fig/container",
718 | "keywords": [
719 | "PSR-11",
720 | "container",
721 | "container-interface",
722 | "container-interop",
723 | "psr"
724 | ],
725 | "support": {
726 | "issues": "https://github.com/php-fig/container/issues",
727 | "source": "https://github.com/php-fig/container/tree/2.0.2"
728 | },
729 | "time": "2021-11-05T16:47:00+00:00"
730 | },
731 | {
732 | "name": "psr/event-dispatcher",
733 | "version": "1.0.0",
734 | "source": {
735 | "type": "git",
736 | "url": "https://github.com/php-fig/event-dispatcher.git",
737 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
738 | },
739 | "dist": {
740 | "type": "zip",
741 | "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
742 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
743 | "shasum": ""
744 | },
745 | "require": {
746 | "php": ">=7.2.0"
747 | },
748 | "type": "library",
749 | "extra": {
750 | "branch-alias": {
751 | "dev-master": "1.0.x-dev"
752 | }
753 | },
754 | "autoload": {
755 | "psr-4": {
756 | "Psr\\EventDispatcher\\": "src/"
757 | }
758 | },
759 | "notification-url": "https://packagist.org/downloads/",
760 | "license": [
761 | "MIT"
762 | ],
763 | "authors": [
764 | {
765 | "name": "PHP-FIG",
766 | "homepage": "http://www.php-fig.org/"
767 | }
768 | ],
769 | "description": "Standard interfaces for event handling.",
770 | "keywords": [
771 | "events",
772 | "psr",
773 | "psr-14"
774 | ],
775 | "support": {
776 | "issues": "https://github.com/php-fig/event-dispatcher/issues",
777 | "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
778 | },
779 | "time": "2019-01-08T18:20:26+00:00"
780 | },
781 | {
782 | "name": "psr/log",
783 | "version": "3.0.0",
784 | "source": {
785 | "type": "git",
786 | "url": "https://github.com/php-fig/log.git",
787 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
788 | },
789 | "dist": {
790 | "type": "zip",
791 | "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
792 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
793 | "shasum": ""
794 | },
795 | "require": {
796 | "php": ">=8.0.0"
797 | },
798 | "type": "library",
799 | "extra": {
800 | "branch-alias": {
801 | "dev-master": "3.x-dev"
802 | }
803 | },
804 | "autoload": {
805 | "psr-4": {
806 | "Psr\\Log\\": "src"
807 | }
808 | },
809 | "notification-url": "https://packagist.org/downloads/",
810 | "license": [
811 | "MIT"
812 | ],
813 | "authors": [
814 | {
815 | "name": "PHP-FIG",
816 | "homepage": "https://www.php-fig.org/"
817 | }
818 | ],
819 | "description": "Common interface for logging libraries",
820 | "homepage": "https://github.com/php-fig/log",
821 | "keywords": [
822 | "log",
823 | "psr",
824 | "psr-3"
825 | ],
826 | "support": {
827 | "source": "https://github.com/php-fig/log/tree/3.0.0"
828 | },
829 | "time": "2021-07-14T16:46:02+00:00"
830 | },
831 | {
832 | "name": "sebastian/diff",
833 | "version": "4.0.4",
834 | "source": {
835 | "type": "git",
836 | "url": "https://github.com/sebastianbergmann/diff.git",
837 | "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
838 | },
839 | "dist": {
840 | "type": "zip",
841 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
842 | "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
843 | "shasum": ""
844 | },
845 | "require": {
846 | "php": ">=7.3"
847 | },
848 | "require-dev": {
849 | "phpunit/phpunit": "^9.3",
850 | "symfony/process": "^4.2 || ^5"
851 | },
852 | "type": "library",
853 | "extra": {
854 | "branch-alias": {
855 | "dev-master": "4.0-dev"
856 | }
857 | },
858 | "autoload": {
859 | "classmap": [
860 | "src/"
861 | ]
862 | },
863 | "notification-url": "https://packagist.org/downloads/",
864 | "license": [
865 | "BSD-3-Clause"
866 | ],
867 | "authors": [
868 | {
869 | "name": "Sebastian Bergmann",
870 | "email": "sebastian@phpunit.de"
871 | },
872 | {
873 | "name": "Kore Nordmann",
874 | "email": "mail@kore-nordmann.de"
875 | }
876 | ],
877 | "description": "Diff implementation",
878 | "homepage": "https://github.com/sebastianbergmann/diff",
879 | "keywords": [
880 | "diff",
881 | "udiff",
882 | "unidiff",
883 | "unified diff"
884 | ],
885 | "support": {
886 | "issues": "https://github.com/sebastianbergmann/diff/issues",
887 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
888 | },
889 | "funding": [
890 | {
891 | "url": "https://github.com/sebastianbergmann",
892 | "type": "github"
893 | }
894 | ],
895 | "time": "2020-10-26T13:10:38+00:00"
896 | },
897 | {
898 | "name": "symfony/console",
899 | "version": "v6.0.17",
900 | "source": {
901 | "type": "git",
902 | "url": "https://github.com/symfony/console.git",
903 | "reference": "2ab307342a7233b9a260edd5ef94087aaca57d18"
904 | },
905 | "dist": {
906 | "type": "zip",
907 | "url": "https://api.github.com/repos/symfony/console/zipball/2ab307342a7233b9a260edd5ef94087aaca57d18",
908 | "reference": "2ab307342a7233b9a260edd5ef94087aaca57d18",
909 | "shasum": ""
910 | },
911 | "require": {
912 | "php": ">=8.0.2",
913 | "symfony/polyfill-mbstring": "~1.0",
914 | "symfony/service-contracts": "^1.1|^2|^3",
915 | "symfony/string": "^5.4|^6.0"
916 | },
917 | "conflict": {
918 | "symfony/dependency-injection": "<5.4",
919 | "symfony/dotenv": "<5.4",
920 | "symfony/event-dispatcher": "<5.4",
921 | "symfony/lock": "<5.4",
922 | "symfony/process": "<5.4"
923 | },
924 | "provide": {
925 | "psr/log-implementation": "1.0|2.0|3.0"
926 | },
927 | "require-dev": {
928 | "psr/log": "^1|^2|^3",
929 | "symfony/config": "^5.4|^6.0",
930 | "symfony/dependency-injection": "^5.4|^6.0",
931 | "symfony/event-dispatcher": "^5.4|^6.0",
932 | "symfony/lock": "^5.4|^6.0",
933 | "symfony/process": "^5.4|^6.0",
934 | "symfony/var-dumper": "^5.4|^6.0"
935 | },
936 | "suggest": {
937 | "psr/log": "For using the console logger",
938 | "symfony/event-dispatcher": "",
939 | "symfony/lock": "",
940 | "symfony/process": ""
941 | },
942 | "type": "library",
943 | "autoload": {
944 | "psr-4": {
945 | "Symfony\\Component\\Console\\": ""
946 | },
947 | "exclude-from-classmap": [
948 | "/Tests/"
949 | ]
950 | },
951 | "notification-url": "https://packagist.org/downloads/",
952 | "license": [
953 | "MIT"
954 | ],
955 | "authors": [
956 | {
957 | "name": "Fabien Potencier",
958 | "email": "fabien@symfony.com"
959 | },
960 | {
961 | "name": "Symfony Community",
962 | "homepage": "https://symfony.com/contributors"
963 | }
964 | ],
965 | "description": "Eases the creation of beautiful and testable command line interfaces",
966 | "homepage": "https://symfony.com",
967 | "keywords": [
968 | "cli",
969 | "command line",
970 | "console",
971 | "terminal"
972 | ],
973 | "support": {
974 | "source": "https://github.com/symfony/console/tree/v6.0.17"
975 | },
976 | "funding": [
977 | {
978 | "url": "https://symfony.com/sponsor",
979 | "type": "custom"
980 | },
981 | {
982 | "url": "https://github.com/fabpot",
983 | "type": "github"
984 | },
985 | {
986 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
987 | "type": "tidelift"
988 | }
989 | ],
990 | "time": "2022-12-28T14:21:34+00:00"
991 | },
992 | {
993 | "name": "symfony/deprecation-contracts",
994 | "version": "v3.0.2",
995 | "source": {
996 | "type": "git",
997 | "url": "https://github.com/symfony/deprecation-contracts.git",
998 | "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c"
999 | },
1000 | "dist": {
1001 | "type": "zip",
1002 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c",
1003 | "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c",
1004 | "shasum": ""
1005 | },
1006 | "require": {
1007 | "php": ">=8.0.2"
1008 | },
1009 | "type": "library",
1010 | "extra": {
1011 | "branch-alias": {
1012 | "dev-main": "3.0-dev"
1013 | },
1014 | "thanks": {
1015 | "name": "symfony/contracts",
1016 | "url": "https://github.com/symfony/contracts"
1017 | }
1018 | },
1019 | "autoload": {
1020 | "files": [
1021 | "function.php"
1022 | ]
1023 | },
1024 | "notification-url": "https://packagist.org/downloads/",
1025 | "license": [
1026 | "MIT"
1027 | ],
1028 | "authors": [
1029 | {
1030 | "name": "Nicolas Grekas",
1031 | "email": "p@tchwork.com"
1032 | },
1033 | {
1034 | "name": "Symfony Community",
1035 | "homepage": "https://symfony.com/contributors"
1036 | }
1037 | ],
1038 | "description": "A generic function and convention to trigger deprecation notices",
1039 | "homepage": "https://symfony.com",
1040 | "support": {
1041 | "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.2"
1042 | },
1043 | "funding": [
1044 | {
1045 | "url": "https://symfony.com/sponsor",
1046 | "type": "custom"
1047 | },
1048 | {
1049 | "url": "https://github.com/fabpot",
1050 | "type": "github"
1051 | },
1052 | {
1053 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1054 | "type": "tidelift"
1055 | }
1056 | ],
1057 | "time": "2022-01-02T09:55:41+00:00"
1058 | },
1059 | {
1060 | "name": "symfony/event-dispatcher",
1061 | "version": "v6.0.17",
1062 | "source": {
1063 | "type": "git",
1064 | "url": "https://github.com/symfony/event-dispatcher.git",
1065 | "reference": "42b3985aa07837c9df36013ec5b965e9f2d480bc"
1066 | },
1067 | "dist": {
1068 | "type": "zip",
1069 | "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/42b3985aa07837c9df36013ec5b965e9f2d480bc",
1070 | "reference": "42b3985aa07837c9df36013ec5b965e9f2d480bc",
1071 | "shasum": ""
1072 | },
1073 | "require": {
1074 | "php": ">=8.0.2",
1075 | "symfony/event-dispatcher-contracts": "^2|^3"
1076 | },
1077 | "conflict": {
1078 | "symfony/dependency-injection": "<5.4"
1079 | },
1080 | "provide": {
1081 | "psr/event-dispatcher-implementation": "1.0",
1082 | "symfony/event-dispatcher-implementation": "2.0|3.0"
1083 | },
1084 | "require-dev": {
1085 | "psr/log": "^1|^2|^3",
1086 | "symfony/config": "^5.4|^6.0",
1087 | "symfony/dependency-injection": "^5.4|^6.0",
1088 | "symfony/error-handler": "^5.4|^6.0",
1089 | "symfony/expression-language": "^5.4|^6.0",
1090 | "symfony/http-foundation": "^5.4|^6.0",
1091 | "symfony/service-contracts": "^1.1|^2|^3",
1092 | "symfony/stopwatch": "^5.4|^6.0"
1093 | },
1094 | "suggest": {
1095 | "symfony/dependency-injection": "",
1096 | "symfony/http-kernel": ""
1097 | },
1098 | "type": "library",
1099 | "autoload": {
1100 | "psr-4": {
1101 | "Symfony\\Component\\EventDispatcher\\": ""
1102 | },
1103 | "exclude-from-classmap": [
1104 | "/Tests/"
1105 | ]
1106 | },
1107 | "notification-url": "https://packagist.org/downloads/",
1108 | "license": [
1109 | "MIT"
1110 | ],
1111 | "authors": [
1112 | {
1113 | "name": "Fabien Potencier",
1114 | "email": "fabien@symfony.com"
1115 | },
1116 | {
1117 | "name": "Symfony Community",
1118 | "homepage": "https://symfony.com/contributors"
1119 | }
1120 | ],
1121 | "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
1122 | "homepage": "https://symfony.com",
1123 | "support": {
1124 | "source": "https://github.com/symfony/event-dispatcher/tree/v6.0.17"
1125 | },
1126 | "funding": [
1127 | {
1128 | "url": "https://symfony.com/sponsor",
1129 | "type": "custom"
1130 | },
1131 | {
1132 | "url": "https://github.com/fabpot",
1133 | "type": "github"
1134 | },
1135 | {
1136 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1137 | "type": "tidelift"
1138 | }
1139 | ],
1140 | "time": "2022-12-14T15:52:41+00:00"
1141 | },
1142 | {
1143 | "name": "symfony/event-dispatcher-contracts",
1144 | "version": "v3.0.2",
1145 | "source": {
1146 | "type": "git",
1147 | "url": "https://github.com/symfony/event-dispatcher-contracts.git",
1148 | "reference": "7bc61cc2db649b4637d331240c5346dcc7708051"
1149 | },
1150 | "dist": {
1151 | "type": "zip",
1152 | "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7bc61cc2db649b4637d331240c5346dcc7708051",
1153 | "reference": "7bc61cc2db649b4637d331240c5346dcc7708051",
1154 | "shasum": ""
1155 | },
1156 | "require": {
1157 | "php": ">=8.0.2",
1158 | "psr/event-dispatcher": "^1"
1159 | },
1160 | "suggest": {
1161 | "symfony/event-dispatcher-implementation": ""
1162 | },
1163 | "type": "library",
1164 | "extra": {
1165 | "branch-alias": {
1166 | "dev-main": "3.0-dev"
1167 | },
1168 | "thanks": {
1169 | "name": "symfony/contracts",
1170 | "url": "https://github.com/symfony/contracts"
1171 | }
1172 | },
1173 | "autoload": {
1174 | "psr-4": {
1175 | "Symfony\\Contracts\\EventDispatcher\\": ""
1176 | }
1177 | },
1178 | "notification-url": "https://packagist.org/downloads/",
1179 | "license": [
1180 | "MIT"
1181 | ],
1182 | "authors": [
1183 | {
1184 | "name": "Nicolas Grekas",
1185 | "email": "p@tchwork.com"
1186 | },
1187 | {
1188 | "name": "Symfony Community",
1189 | "homepage": "https://symfony.com/contributors"
1190 | }
1191 | ],
1192 | "description": "Generic abstractions related to dispatching event",
1193 | "homepage": "https://symfony.com",
1194 | "keywords": [
1195 | "abstractions",
1196 | "contracts",
1197 | "decoupling",
1198 | "interfaces",
1199 | "interoperability",
1200 | "standards"
1201 | ],
1202 | "support": {
1203 | "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.0.2"
1204 | },
1205 | "funding": [
1206 | {
1207 | "url": "https://symfony.com/sponsor",
1208 | "type": "custom"
1209 | },
1210 | {
1211 | "url": "https://github.com/fabpot",
1212 | "type": "github"
1213 | },
1214 | {
1215 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1216 | "type": "tidelift"
1217 | }
1218 | ],
1219 | "time": "2022-01-02T09:55:41+00:00"
1220 | },
1221 | {
1222 | "name": "symfony/filesystem",
1223 | "version": "v6.0.13",
1224 | "source": {
1225 | "type": "git",
1226 | "url": "https://github.com/symfony/filesystem.git",
1227 | "reference": "3adca49133bd055ebe6011ed1e012be3c908af79"
1228 | },
1229 | "dist": {
1230 | "type": "zip",
1231 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/3adca49133bd055ebe6011ed1e012be3c908af79",
1232 | "reference": "3adca49133bd055ebe6011ed1e012be3c908af79",
1233 | "shasum": ""
1234 | },
1235 | "require": {
1236 | "php": ">=8.0.2",
1237 | "symfony/polyfill-ctype": "~1.8",
1238 | "symfony/polyfill-mbstring": "~1.8"
1239 | },
1240 | "type": "library",
1241 | "autoload": {
1242 | "psr-4": {
1243 | "Symfony\\Component\\Filesystem\\": ""
1244 | },
1245 | "exclude-from-classmap": [
1246 | "/Tests/"
1247 | ]
1248 | },
1249 | "notification-url": "https://packagist.org/downloads/",
1250 | "license": [
1251 | "MIT"
1252 | ],
1253 | "authors": [
1254 | {
1255 | "name": "Fabien Potencier",
1256 | "email": "fabien@symfony.com"
1257 | },
1258 | {
1259 | "name": "Symfony Community",
1260 | "homepage": "https://symfony.com/contributors"
1261 | }
1262 | ],
1263 | "description": "Provides basic utilities for the filesystem",
1264 | "homepage": "https://symfony.com",
1265 | "support": {
1266 | "source": "https://github.com/symfony/filesystem/tree/v6.0.13"
1267 | },
1268 | "funding": [
1269 | {
1270 | "url": "https://symfony.com/sponsor",
1271 | "type": "custom"
1272 | },
1273 | {
1274 | "url": "https://github.com/fabpot",
1275 | "type": "github"
1276 | },
1277 | {
1278 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1279 | "type": "tidelift"
1280 | }
1281 | ],
1282 | "time": "2022-09-21T20:25:27+00:00"
1283 | },
1284 | {
1285 | "name": "symfony/finder",
1286 | "version": "v6.0.17",
1287 | "source": {
1288 | "type": "git",
1289 | "url": "https://github.com/symfony/finder.git",
1290 | "reference": "d467d625fc88f7cebf96f495e588a7196a669db1"
1291 | },
1292 | "dist": {
1293 | "type": "zip",
1294 | "url": "https://api.github.com/repos/symfony/finder/zipball/d467d625fc88f7cebf96f495e588a7196a669db1",
1295 | "reference": "d467d625fc88f7cebf96f495e588a7196a669db1",
1296 | "shasum": ""
1297 | },
1298 | "require": {
1299 | "php": ">=8.0.2"
1300 | },
1301 | "type": "library",
1302 | "autoload": {
1303 | "psr-4": {
1304 | "Symfony\\Component\\Finder\\": ""
1305 | },
1306 | "exclude-from-classmap": [
1307 | "/Tests/"
1308 | ]
1309 | },
1310 | "notification-url": "https://packagist.org/downloads/",
1311 | "license": [
1312 | "MIT"
1313 | ],
1314 | "authors": [
1315 | {
1316 | "name": "Fabien Potencier",
1317 | "email": "fabien@symfony.com"
1318 | },
1319 | {
1320 | "name": "Symfony Community",
1321 | "homepage": "https://symfony.com/contributors"
1322 | }
1323 | ],
1324 | "description": "Finds files and directories via an intuitive fluent interface",
1325 | "homepage": "https://symfony.com",
1326 | "support": {
1327 | "source": "https://github.com/symfony/finder/tree/v6.0.17"
1328 | },
1329 | "funding": [
1330 | {
1331 | "url": "https://symfony.com/sponsor",
1332 | "type": "custom"
1333 | },
1334 | {
1335 | "url": "https://github.com/fabpot",
1336 | "type": "github"
1337 | },
1338 | {
1339 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1340 | "type": "tidelift"
1341 | }
1342 | ],
1343 | "time": "2022-12-22T17:53:58+00:00"
1344 | },
1345 | {
1346 | "name": "symfony/options-resolver",
1347 | "version": "v6.0.3",
1348 | "source": {
1349 | "type": "git",
1350 | "url": "https://github.com/symfony/options-resolver.git",
1351 | "reference": "51f7006670febe4cbcbae177cbffe93ff833250d"
1352 | },
1353 | "dist": {
1354 | "type": "zip",
1355 | "url": "https://api.github.com/repos/symfony/options-resolver/zipball/51f7006670febe4cbcbae177cbffe93ff833250d",
1356 | "reference": "51f7006670febe4cbcbae177cbffe93ff833250d",
1357 | "shasum": ""
1358 | },
1359 | "require": {
1360 | "php": ">=8.0.2",
1361 | "symfony/deprecation-contracts": "^2.1|^3"
1362 | },
1363 | "type": "library",
1364 | "autoload": {
1365 | "psr-4": {
1366 | "Symfony\\Component\\OptionsResolver\\": ""
1367 | },
1368 | "exclude-from-classmap": [
1369 | "/Tests/"
1370 | ]
1371 | },
1372 | "notification-url": "https://packagist.org/downloads/",
1373 | "license": [
1374 | "MIT"
1375 | ],
1376 | "authors": [
1377 | {
1378 | "name": "Fabien Potencier",
1379 | "email": "fabien@symfony.com"
1380 | },
1381 | {
1382 | "name": "Symfony Community",
1383 | "homepage": "https://symfony.com/contributors"
1384 | }
1385 | ],
1386 | "description": "Provides an improved replacement for the array_replace PHP function",
1387 | "homepage": "https://symfony.com",
1388 | "keywords": [
1389 | "config",
1390 | "configuration",
1391 | "options"
1392 | ],
1393 | "support": {
1394 | "source": "https://github.com/symfony/options-resolver/tree/v6.0.3"
1395 | },
1396 | "funding": [
1397 | {
1398 | "url": "https://symfony.com/sponsor",
1399 | "type": "custom"
1400 | },
1401 | {
1402 | "url": "https://github.com/fabpot",
1403 | "type": "github"
1404 | },
1405 | {
1406 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1407 | "type": "tidelift"
1408 | }
1409 | ],
1410 | "time": "2022-01-02T09:55:41+00:00"
1411 | },
1412 | {
1413 | "name": "symfony/polyfill-ctype",
1414 | "version": "v1.27.0",
1415 | "source": {
1416 | "type": "git",
1417 | "url": "https://github.com/symfony/polyfill-ctype.git",
1418 | "reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
1419 | },
1420 | "dist": {
1421 | "type": "zip",
1422 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
1423 | "reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
1424 | "shasum": ""
1425 | },
1426 | "require": {
1427 | "php": ">=7.1"
1428 | },
1429 | "provide": {
1430 | "ext-ctype": "*"
1431 | },
1432 | "suggest": {
1433 | "ext-ctype": "For best performance"
1434 | },
1435 | "type": "library",
1436 | "extra": {
1437 | "branch-alias": {
1438 | "dev-main": "1.27-dev"
1439 | },
1440 | "thanks": {
1441 | "name": "symfony/polyfill",
1442 | "url": "https://github.com/symfony/polyfill"
1443 | }
1444 | },
1445 | "autoload": {
1446 | "files": [
1447 | "bootstrap.php"
1448 | ],
1449 | "psr-4": {
1450 | "Symfony\\Polyfill\\Ctype\\": ""
1451 | }
1452 | },
1453 | "notification-url": "https://packagist.org/downloads/",
1454 | "license": [
1455 | "MIT"
1456 | ],
1457 | "authors": [
1458 | {
1459 | "name": "Gert de Pagter",
1460 | "email": "BackEndTea@gmail.com"
1461 | },
1462 | {
1463 | "name": "Symfony Community",
1464 | "homepage": "https://symfony.com/contributors"
1465 | }
1466 | ],
1467 | "description": "Symfony polyfill for ctype functions",
1468 | "homepage": "https://symfony.com",
1469 | "keywords": [
1470 | "compatibility",
1471 | "ctype",
1472 | "polyfill",
1473 | "portable"
1474 | ],
1475 | "support": {
1476 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
1477 | },
1478 | "funding": [
1479 | {
1480 | "url": "https://symfony.com/sponsor",
1481 | "type": "custom"
1482 | },
1483 | {
1484 | "url": "https://github.com/fabpot",
1485 | "type": "github"
1486 | },
1487 | {
1488 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1489 | "type": "tidelift"
1490 | }
1491 | ],
1492 | "time": "2022-11-03T14:55:06+00:00"
1493 | },
1494 | {
1495 | "name": "symfony/polyfill-intl-grapheme",
1496 | "version": "v1.27.0",
1497 | "source": {
1498 | "type": "git",
1499 | "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
1500 | "reference": "511a08c03c1960e08a883f4cffcacd219b758354"
1501 | },
1502 | "dist": {
1503 | "type": "zip",
1504 | "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
1505 | "reference": "511a08c03c1960e08a883f4cffcacd219b758354",
1506 | "shasum": ""
1507 | },
1508 | "require": {
1509 | "php": ">=7.1"
1510 | },
1511 | "suggest": {
1512 | "ext-intl": "For best performance"
1513 | },
1514 | "type": "library",
1515 | "extra": {
1516 | "branch-alias": {
1517 | "dev-main": "1.27-dev"
1518 | },
1519 | "thanks": {
1520 | "name": "symfony/polyfill",
1521 | "url": "https://github.com/symfony/polyfill"
1522 | }
1523 | },
1524 | "autoload": {
1525 | "files": [
1526 | "bootstrap.php"
1527 | ],
1528 | "psr-4": {
1529 | "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
1530 | }
1531 | },
1532 | "notification-url": "https://packagist.org/downloads/",
1533 | "license": [
1534 | "MIT"
1535 | ],
1536 | "authors": [
1537 | {
1538 | "name": "Nicolas Grekas",
1539 | "email": "p@tchwork.com"
1540 | },
1541 | {
1542 | "name": "Symfony Community",
1543 | "homepage": "https://symfony.com/contributors"
1544 | }
1545 | ],
1546 | "description": "Symfony polyfill for intl's grapheme_* functions",
1547 | "homepage": "https://symfony.com",
1548 | "keywords": [
1549 | "compatibility",
1550 | "grapheme",
1551 | "intl",
1552 | "polyfill",
1553 | "portable",
1554 | "shim"
1555 | ],
1556 | "support": {
1557 | "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
1558 | },
1559 | "funding": [
1560 | {
1561 | "url": "https://symfony.com/sponsor",
1562 | "type": "custom"
1563 | },
1564 | {
1565 | "url": "https://github.com/fabpot",
1566 | "type": "github"
1567 | },
1568 | {
1569 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1570 | "type": "tidelift"
1571 | }
1572 | ],
1573 | "time": "2022-11-03T14:55:06+00:00"
1574 | },
1575 | {
1576 | "name": "symfony/polyfill-intl-normalizer",
1577 | "version": "v1.27.0",
1578 | "source": {
1579 | "type": "git",
1580 | "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
1581 | "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
1582 | },
1583 | "dist": {
1584 | "type": "zip",
1585 | "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
1586 | "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
1587 | "shasum": ""
1588 | },
1589 | "require": {
1590 | "php": ">=7.1"
1591 | },
1592 | "suggest": {
1593 | "ext-intl": "For best performance"
1594 | },
1595 | "type": "library",
1596 | "extra": {
1597 | "branch-alias": {
1598 | "dev-main": "1.27-dev"
1599 | },
1600 | "thanks": {
1601 | "name": "symfony/polyfill",
1602 | "url": "https://github.com/symfony/polyfill"
1603 | }
1604 | },
1605 | "autoload": {
1606 | "files": [
1607 | "bootstrap.php"
1608 | ],
1609 | "psr-4": {
1610 | "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
1611 | },
1612 | "classmap": [
1613 | "Resources/stubs"
1614 | ]
1615 | },
1616 | "notification-url": "https://packagist.org/downloads/",
1617 | "license": [
1618 | "MIT"
1619 | ],
1620 | "authors": [
1621 | {
1622 | "name": "Nicolas Grekas",
1623 | "email": "p@tchwork.com"
1624 | },
1625 | {
1626 | "name": "Symfony Community",
1627 | "homepage": "https://symfony.com/contributors"
1628 | }
1629 | ],
1630 | "description": "Symfony polyfill for intl's Normalizer class and related functions",
1631 | "homepage": "https://symfony.com",
1632 | "keywords": [
1633 | "compatibility",
1634 | "intl",
1635 | "normalizer",
1636 | "polyfill",
1637 | "portable",
1638 | "shim"
1639 | ],
1640 | "support": {
1641 | "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
1642 | },
1643 | "funding": [
1644 | {
1645 | "url": "https://symfony.com/sponsor",
1646 | "type": "custom"
1647 | },
1648 | {
1649 | "url": "https://github.com/fabpot",
1650 | "type": "github"
1651 | },
1652 | {
1653 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1654 | "type": "tidelift"
1655 | }
1656 | ],
1657 | "time": "2022-11-03T14:55:06+00:00"
1658 | },
1659 | {
1660 | "name": "symfony/polyfill-mbstring",
1661 | "version": "v1.27.0",
1662 | "source": {
1663 | "type": "git",
1664 | "url": "https://github.com/symfony/polyfill-mbstring.git",
1665 | "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
1666 | },
1667 | "dist": {
1668 | "type": "zip",
1669 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
1670 | "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
1671 | "shasum": ""
1672 | },
1673 | "require": {
1674 | "php": ">=7.1"
1675 | },
1676 | "provide": {
1677 | "ext-mbstring": "*"
1678 | },
1679 | "suggest": {
1680 | "ext-mbstring": "For best performance"
1681 | },
1682 | "type": "library",
1683 | "extra": {
1684 | "branch-alias": {
1685 | "dev-main": "1.27-dev"
1686 | },
1687 | "thanks": {
1688 | "name": "symfony/polyfill",
1689 | "url": "https://github.com/symfony/polyfill"
1690 | }
1691 | },
1692 | "autoload": {
1693 | "files": [
1694 | "bootstrap.php"
1695 | ],
1696 | "psr-4": {
1697 | "Symfony\\Polyfill\\Mbstring\\": ""
1698 | }
1699 | },
1700 | "notification-url": "https://packagist.org/downloads/",
1701 | "license": [
1702 | "MIT"
1703 | ],
1704 | "authors": [
1705 | {
1706 | "name": "Nicolas Grekas",
1707 | "email": "p@tchwork.com"
1708 | },
1709 | {
1710 | "name": "Symfony Community",
1711 | "homepage": "https://symfony.com/contributors"
1712 | }
1713 | ],
1714 | "description": "Symfony polyfill for the Mbstring extension",
1715 | "homepage": "https://symfony.com",
1716 | "keywords": [
1717 | "compatibility",
1718 | "mbstring",
1719 | "polyfill",
1720 | "portable",
1721 | "shim"
1722 | ],
1723 | "support": {
1724 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
1725 | },
1726 | "funding": [
1727 | {
1728 | "url": "https://symfony.com/sponsor",
1729 | "type": "custom"
1730 | },
1731 | {
1732 | "url": "https://github.com/fabpot",
1733 | "type": "github"
1734 | },
1735 | {
1736 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1737 | "type": "tidelift"
1738 | }
1739 | ],
1740 | "time": "2022-11-03T14:55:06+00:00"
1741 | },
1742 | {
1743 | "name": "symfony/polyfill-php80",
1744 | "version": "v1.27.0",
1745 | "source": {
1746 | "type": "git",
1747 | "url": "https://github.com/symfony/polyfill-php80.git",
1748 | "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
1749 | },
1750 | "dist": {
1751 | "type": "zip",
1752 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
1753 | "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
1754 | "shasum": ""
1755 | },
1756 | "require": {
1757 | "php": ">=7.1"
1758 | },
1759 | "type": "library",
1760 | "extra": {
1761 | "branch-alias": {
1762 | "dev-main": "1.27-dev"
1763 | },
1764 | "thanks": {
1765 | "name": "symfony/polyfill",
1766 | "url": "https://github.com/symfony/polyfill"
1767 | }
1768 | },
1769 | "autoload": {
1770 | "files": [
1771 | "bootstrap.php"
1772 | ],
1773 | "psr-4": {
1774 | "Symfony\\Polyfill\\Php80\\": ""
1775 | },
1776 | "classmap": [
1777 | "Resources/stubs"
1778 | ]
1779 | },
1780 | "notification-url": "https://packagist.org/downloads/",
1781 | "license": [
1782 | "MIT"
1783 | ],
1784 | "authors": [
1785 | {
1786 | "name": "Ion Bazan",
1787 | "email": "ion.bazan@gmail.com"
1788 | },
1789 | {
1790 | "name": "Nicolas Grekas",
1791 | "email": "p@tchwork.com"
1792 | },
1793 | {
1794 | "name": "Symfony Community",
1795 | "homepage": "https://symfony.com/contributors"
1796 | }
1797 | ],
1798 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
1799 | "homepage": "https://symfony.com",
1800 | "keywords": [
1801 | "compatibility",
1802 | "polyfill",
1803 | "portable",
1804 | "shim"
1805 | ],
1806 | "support": {
1807 | "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
1808 | },
1809 | "funding": [
1810 | {
1811 | "url": "https://symfony.com/sponsor",
1812 | "type": "custom"
1813 | },
1814 | {
1815 | "url": "https://github.com/fabpot",
1816 | "type": "github"
1817 | },
1818 | {
1819 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1820 | "type": "tidelift"
1821 | }
1822 | ],
1823 | "time": "2022-11-03T14:55:06+00:00"
1824 | },
1825 | {
1826 | "name": "symfony/polyfill-php81",
1827 | "version": "v1.27.0",
1828 | "source": {
1829 | "type": "git",
1830 | "url": "https://github.com/symfony/polyfill-php81.git",
1831 | "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a"
1832 | },
1833 | "dist": {
1834 | "type": "zip",
1835 | "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a",
1836 | "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a",
1837 | "shasum": ""
1838 | },
1839 | "require": {
1840 | "php": ">=7.1"
1841 | },
1842 | "type": "library",
1843 | "extra": {
1844 | "branch-alias": {
1845 | "dev-main": "1.27-dev"
1846 | },
1847 | "thanks": {
1848 | "name": "symfony/polyfill",
1849 | "url": "https://github.com/symfony/polyfill"
1850 | }
1851 | },
1852 | "autoload": {
1853 | "files": [
1854 | "bootstrap.php"
1855 | ],
1856 | "psr-4": {
1857 | "Symfony\\Polyfill\\Php81\\": ""
1858 | },
1859 | "classmap": [
1860 | "Resources/stubs"
1861 | ]
1862 | },
1863 | "notification-url": "https://packagist.org/downloads/",
1864 | "license": [
1865 | "MIT"
1866 | ],
1867 | "authors": [
1868 | {
1869 | "name": "Nicolas Grekas",
1870 | "email": "p@tchwork.com"
1871 | },
1872 | {
1873 | "name": "Symfony Community",
1874 | "homepage": "https://symfony.com/contributors"
1875 | }
1876 | ],
1877 | "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
1878 | "homepage": "https://symfony.com",
1879 | "keywords": [
1880 | "compatibility",
1881 | "polyfill",
1882 | "portable",
1883 | "shim"
1884 | ],
1885 | "support": {
1886 | "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
1887 | },
1888 | "funding": [
1889 | {
1890 | "url": "https://symfony.com/sponsor",
1891 | "type": "custom"
1892 | },
1893 | {
1894 | "url": "https://github.com/fabpot",
1895 | "type": "github"
1896 | },
1897 | {
1898 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1899 | "type": "tidelift"
1900 | }
1901 | ],
1902 | "time": "2022-11-03T14:55:06+00:00"
1903 | },
1904 | {
1905 | "name": "symfony/process",
1906 | "version": "v6.0.11",
1907 | "source": {
1908 | "type": "git",
1909 | "url": "https://github.com/symfony/process.git",
1910 | "reference": "44270a08ccb664143dede554ff1c00aaa2247a43"
1911 | },
1912 | "dist": {
1913 | "type": "zip",
1914 | "url": "https://api.github.com/repos/symfony/process/zipball/44270a08ccb664143dede554ff1c00aaa2247a43",
1915 | "reference": "44270a08ccb664143dede554ff1c00aaa2247a43",
1916 | "shasum": ""
1917 | },
1918 | "require": {
1919 | "php": ">=8.0.2"
1920 | },
1921 | "type": "library",
1922 | "autoload": {
1923 | "psr-4": {
1924 | "Symfony\\Component\\Process\\": ""
1925 | },
1926 | "exclude-from-classmap": [
1927 | "/Tests/"
1928 | ]
1929 | },
1930 | "notification-url": "https://packagist.org/downloads/",
1931 | "license": [
1932 | "MIT"
1933 | ],
1934 | "authors": [
1935 | {
1936 | "name": "Fabien Potencier",
1937 | "email": "fabien@symfony.com"
1938 | },
1939 | {
1940 | "name": "Symfony Community",
1941 | "homepage": "https://symfony.com/contributors"
1942 | }
1943 | ],
1944 | "description": "Executes commands in sub-processes",
1945 | "homepage": "https://symfony.com",
1946 | "support": {
1947 | "source": "https://github.com/symfony/process/tree/v6.0.11"
1948 | },
1949 | "funding": [
1950 | {
1951 | "url": "https://symfony.com/sponsor",
1952 | "type": "custom"
1953 | },
1954 | {
1955 | "url": "https://github.com/fabpot",
1956 | "type": "github"
1957 | },
1958 | {
1959 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1960 | "type": "tidelift"
1961 | }
1962 | ],
1963 | "time": "2022-06-27T17:10:44+00:00"
1964 | },
1965 | {
1966 | "name": "symfony/service-contracts",
1967 | "version": "v3.0.2",
1968 | "source": {
1969 | "type": "git",
1970 | "url": "https://github.com/symfony/service-contracts.git",
1971 | "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66"
1972 | },
1973 | "dist": {
1974 | "type": "zip",
1975 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d78d39c1599bd1188b8e26bb341da52c3c6d8a66",
1976 | "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66",
1977 | "shasum": ""
1978 | },
1979 | "require": {
1980 | "php": ">=8.0.2",
1981 | "psr/container": "^2.0"
1982 | },
1983 | "conflict": {
1984 | "ext-psr": "<1.1|>=2"
1985 | },
1986 | "suggest": {
1987 | "symfony/service-implementation": ""
1988 | },
1989 | "type": "library",
1990 | "extra": {
1991 | "branch-alias": {
1992 | "dev-main": "3.0-dev"
1993 | },
1994 | "thanks": {
1995 | "name": "symfony/contracts",
1996 | "url": "https://github.com/symfony/contracts"
1997 | }
1998 | },
1999 | "autoload": {
2000 | "psr-4": {
2001 | "Symfony\\Contracts\\Service\\": ""
2002 | }
2003 | },
2004 | "notification-url": "https://packagist.org/downloads/",
2005 | "license": [
2006 | "MIT"
2007 | ],
2008 | "authors": [
2009 | {
2010 | "name": "Nicolas Grekas",
2011 | "email": "p@tchwork.com"
2012 | },
2013 | {
2014 | "name": "Symfony Community",
2015 | "homepage": "https://symfony.com/contributors"
2016 | }
2017 | ],
2018 | "description": "Generic abstractions related to writing services",
2019 | "homepage": "https://symfony.com",
2020 | "keywords": [
2021 | "abstractions",
2022 | "contracts",
2023 | "decoupling",
2024 | "interfaces",
2025 | "interoperability",
2026 | "standards"
2027 | ],
2028 | "support": {
2029 | "source": "https://github.com/symfony/service-contracts/tree/v3.0.2"
2030 | },
2031 | "funding": [
2032 | {
2033 | "url": "https://symfony.com/sponsor",
2034 | "type": "custom"
2035 | },
2036 | {
2037 | "url": "https://github.com/fabpot",
2038 | "type": "github"
2039 | },
2040 | {
2041 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2042 | "type": "tidelift"
2043 | }
2044 | ],
2045 | "time": "2022-05-30T19:17:58+00:00"
2046 | },
2047 | {
2048 | "name": "symfony/stopwatch",
2049 | "version": "v6.0.13",
2050 | "source": {
2051 | "type": "git",
2052 | "url": "https://github.com/symfony/stopwatch.git",
2053 | "reference": "7554fde6848af5ef1178f8ccbdbdb8ae1092c70a"
2054 | },
2055 | "dist": {
2056 | "type": "zip",
2057 | "url": "https://api.github.com/repos/symfony/stopwatch/zipball/7554fde6848af5ef1178f8ccbdbdb8ae1092c70a",
2058 | "reference": "7554fde6848af5ef1178f8ccbdbdb8ae1092c70a",
2059 | "shasum": ""
2060 | },
2061 | "require": {
2062 | "php": ">=8.0.2",
2063 | "symfony/service-contracts": "^1|^2|^3"
2064 | },
2065 | "type": "library",
2066 | "autoload": {
2067 | "psr-4": {
2068 | "Symfony\\Component\\Stopwatch\\": ""
2069 | },
2070 | "exclude-from-classmap": [
2071 | "/Tests/"
2072 | ]
2073 | },
2074 | "notification-url": "https://packagist.org/downloads/",
2075 | "license": [
2076 | "MIT"
2077 | ],
2078 | "authors": [
2079 | {
2080 | "name": "Fabien Potencier",
2081 | "email": "fabien@symfony.com"
2082 | },
2083 | {
2084 | "name": "Symfony Community",
2085 | "homepage": "https://symfony.com/contributors"
2086 | }
2087 | ],
2088 | "description": "Provides a way to profile code",
2089 | "homepage": "https://symfony.com",
2090 | "support": {
2091 | "source": "https://github.com/symfony/stopwatch/tree/v6.0.13"
2092 | },
2093 | "funding": [
2094 | {
2095 | "url": "https://symfony.com/sponsor",
2096 | "type": "custom"
2097 | },
2098 | {
2099 | "url": "https://github.com/fabpot",
2100 | "type": "github"
2101 | },
2102 | {
2103 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2104 | "type": "tidelift"
2105 | }
2106 | ],
2107 | "time": "2022-09-28T15:52:47+00:00"
2108 | },
2109 | {
2110 | "name": "symfony/string",
2111 | "version": "v6.0.17",
2112 | "source": {
2113 | "type": "git",
2114 | "url": "https://github.com/symfony/string.git",
2115 | "reference": "3f57003dd8a67ed76870cc03092f8501db7788d9"
2116 | },
2117 | "dist": {
2118 | "type": "zip",
2119 | "url": "https://api.github.com/repos/symfony/string/zipball/3f57003dd8a67ed76870cc03092f8501db7788d9",
2120 | "reference": "3f57003dd8a67ed76870cc03092f8501db7788d9",
2121 | "shasum": ""
2122 | },
2123 | "require": {
2124 | "php": ">=8.0.2",
2125 | "symfony/polyfill-ctype": "~1.8",
2126 | "symfony/polyfill-intl-grapheme": "~1.0",
2127 | "symfony/polyfill-intl-normalizer": "~1.0",
2128 | "symfony/polyfill-mbstring": "~1.0"
2129 | },
2130 | "conflict": {
2131 | "symfony/translation-contracts": "<2.0"
2132 | },
2133 | "require-dev": {
2134 | "symfony/error-handler": "^5.4|^6.0",
2135 | "symfony/http-client": "^5.4|^6.0",
2136 | "symfony/translation-contracts": "^2.0|^3.0",
2137 | "symfony/var-exporter": "^5.4|^6.0"
2138 | },
2139 | "type": "library",
2140 | "autoload": {
2141 | "files": [
2142 | "Resources/functions.php"
2143 | ],
2144 | "psr-4": {
2145 | "Symfony\\Component\\String\\": ""
2146 | },
2147 | "exclude-from-classmap": [
2148 | "/Tests/"
2149 | ]
2150 | },
2151 | "notification-url": "https://packagist.org/downloads/",
2152 | "license": [
2153 | "MIT"
2154 | ],
2155 | "authors": [
2156 | {
2157 | "name": "Nicolas Grekas",
2158 | "email": "p@tchwork.com"
2159 | },
2160 | {
2161 | "name": "Symfony Community",
2162 | "homepage": "https://symfony.com/contributors"
2163 | }
2164 | ],
2165 | "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
2166 | "homepage": "https://symfony.com",
2167 | "keywords": [
2168 | "grapheme",
2169 | "i18n",
2170 | "string",
2171 | "unicode",
2172 | "utf-8",
2173 | "utf8"
2174 | ],
2175 | "support": {
2176 | "source": "https://github.com/symfony/string/tree/v6.0.17"
2177 | },
2178 | "funding": [
2179 | {
2180 | "url": "https://symfony.com/sponsor",
2181 | "type": "custom"
2182 | },
2183 | {
2184 | "url": "https://github.com/fabpot",
2185 | "type": "github"
2186 | },
2187 | {
2188 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
2189 | "type": "tidelift"
2190 | }
2191 | ],
2192 | "time": "2022-12-14T15:52:41+00:00"
2193 | }
2194 | ],
2195 | "aliases": [],
2196 | "minimum-stability": "stable",
2197 | "stability-flags": {},
2198 | "prefer-stable": false,
2199 | "prefer-lowest": false,
2200 | "platform": {
2201 | "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
2202 | },
2203 | "platform-dev": {},
2204 | "plugin-api-version": "2.6.0"
2205 | }
2206 |
--------------------------------------------------------------------------------