.phpstorm.meta.php 0000644 00000002154 13721511157 0010141 0 ustar 00 generateProxy(
new ReflectionClass(SayHello::class),
new ClassGenerator('ProxyClassName')
);
eval('generate());
$proxyName = $proxyClass->getName();
$object = new ProxyClassName(); // echoes "Hello!"
var_dump($object); // a proxy object
```
If you still want to manually build a proxy (without factories), a
`public static staticProxyConstructor` method is added to the generated proxy classes.
#### Friend classes support
You can now access state of "friend objects" at any time.
```php
class EmailAddress
{
private $address;
public function __construct(string $address)
{
assertEmail($address);
$this->address = $address;
}
public function equalsTo(EmailAddress $other)
{
return $this->address === $other->address;
}
}
```
When using lazy-loading or access-interceptors, the `equalsTo` method will
properly work, as even `protected` and `private` access are now correctly proxied.
#### Ghost objects now only lazy-load on state-access
Lazy loading ghost objects now trigger lazy-loading only when their state is accessed.
This also implies that lazy loading ghost objects cannot be used with interfaces anymore.
```php
class AccessPolicy
{
private $policyName;
/**
* Calling this method WILL cause lazy-loading, when using a ghost object,
* as the method is accessing the object's state
*/
public function getPolicyName() : string
{
return $this->policyName;
}
/**
* Calling this method WILL NOT cause lazy-loading, when using a ghost object,
* as the method is not reading any from the object.
*/
public function allowAccess() : bool
{
return false;
}
}
```
#### Faster ghost object state initialization
Lazy loading ghost objects can now be initialized in a more efficient way, by avoiding
reflection or setters:
```php
class Foo
{
private $a;
protected $b;
public $c;
}
$factory = new \ProxyManager\Factory\LazyLoadingGhostFactory();
$proxy = $factory-createProxy(
Foo::class,
function (
GhostObjectInterface $proxy,
string $method,
array $parameters,
& $initializer,
array $properties
) {
$initializer = null;
$properties["\0Foo\0a"] = 'abc';
$properties["\0*\0b"] = 'def';
$properties['c'] = 'ghi';
return true;
}
);
$reflectionA = new ReflectionProperty(Foo::class, 'a');
$reflectionA->setAccessible(true);
var_dump($reflectionA->getValue($proxy)); // dumps "abc"
$reflectionB = new ReflectionProperty(Foo::class, 'b');
$reflectionB->setAccessible(true);
var_dump($reflectionB->getValue($proxy)); // dumps "def"
var_dump($proxy->c); // dumps "ghi"
```
#### Skipping lazy-loaded properties in generated proxies
Lazy loading ghost objects can now skip lazy-loading for certain properties.
This is especially useful when you have properties that are always available,
such as identifiers of entities:
```php
class User
{
private $id;
private $username;
public function getId() : int
{
return $this->id;
}
public function getUsername() : string
{
return $this->username;
}
}
/* @var $proxy User */
$proxy = (new \ProxyManager\Factory\LazyLoadingGhostFactory())->createProxy(
User::class,
function (
GhostObjectInterface $proxy,
string $method,
array $parameters,
& $initializer,
array $properties
) {
$initializer = null;
var_dump('Triggered lazy-loading!');
$properties["\0User\0username"] = 'Ocramius';
return true;
},
[
'skippedProperties' => [
"\0User\0id",
],
]
);
$idReflection = new \ReflectionProperty(User::class, 'id');
$idReflection->setAccessible(true);
$idReflection->setValue($proxy, 123);
var_dump($proxy->getId()); // 123
var_dump($proxy->getUsername()); // "Triggered lazy-loading!", then "Ocramius"
```
#### Proxies are now always generated on-the-fly by default
Proxies are now automatically generated any time you require them: no configuration
needed. If you want to gain better performance, you may still want to read
the [tuning for production docs](docs/tuning-for-production.md).
#### Proxy names are now hashed, simplified signature is attached to them
Proxy classes now have shorter names, as the parameters used to generate them are
hashed into their name. A signature is attached to proxy classes (as a private static
property) so that proxy classes aren't re-used across library updates.
Upgrading ProxyManager will now cause all proxies to be re-generated automatically,
while the old proxy files are going to be ignored.
LICENSE 0000644 00000002041 13721511157 0005551 0 ustar 00 Copyright (c) 2013 Marco Pivetta
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
README.md 0000644 00000005257 13721511157 0006037 0 ustar 00 # Proxy Manager
This library aims to provide abstraction for generating various kinds of
[proxy classes](http://ocramius.github.io/presentations/proxy-pattern-in-php/).
![ProxyManager](https://raw.githubusercontent.com/Ocramius/ProxyManager/917bf1698243a1079aaa27ed8ea08c2aef09f4cb/proxy-manager.png)
[![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2FOcramius%2FProxyManager%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/Ocramius/ProxyManager/master)
[![Type Coverage](https://shepherd.dev/github/Ocramius/ProxyManager/coverage.svg)](https://shepherd.dev/github/Ocramius/ProxyManager)
[![Total Downloads](https://poser.pugx.org/ocramius/proxy-manager/downloads.png)](https://packagist.org/packages/ocramius/proxy-manager)
[![Latest Stable Version](https://poser.pugx.org/ocramius/proxy-manager/v/stable.png)](https://packagist.org/packages/ocramius/proxy-manager)
[![Latest Unstable Version](https://poser.pugx.org/ocramius/proxy-manager/v/unstable.png)](https://packagist.org/packages/ocramius/proxy-manager)
## Documentation
You can learn about the proxy pattern and how to use the **ProxyManager** in the [docs](docs).
## ocramius/proxy-manager for enterprise
Available as part of the Tidelift Subscription.
The maintainer of ocramius/proxy-manager and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-ocramius-proxy-manager?utm_source=packagist-ocramius-proxy-manager&utm_medium=referral&utm_campaign=enterprise&utm_term=repo).
You can also contact the maintainer at ocramius@gmail.com for looking into issues related to this package
in your private projects.
## Installation
The suggested installation method is via [composer](https://getcomposer.org/):
```sh
php composer.phar require ocramius/proxy-manager
```
## Proxy example
Here's how you build a lazy loadable object with ProxyManager using a *Virtual Proxy*
```php
$factory = new \ProxyManager\Factory\LazyLoadingValueHolderFactory();
$proxy = $factory->createProxy(
\MyApp\HeavyComplexObject::class,
function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) {
$wrappedObject = new \MyApp\HeavyComplexObject(); // instantiation logic here
$initializer = null; // turning off further lazy initialization
}
);
$proxy->doFoo();
```
See the [documentation](docs) for more supported proxy types and examples.
SECURITY.md 0000644 00000000301 13721511157 0006332 0 ustar 00 ## Security contact information
To report a security vulnerability, please use the
[Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.
STABILITY.md 0000644 00000000646 13721511157 0006443 0 ustar 00 ---
title: Stability
---
This is a list of supported versions, with their expected release/support time-frames:
# 2.0.x
* Release date: 2016-01-30
* Bug fixes: till 2017-12-31
* Security fixes: till 2018-12-31
# 1.0.x
* Release date: 2014-12-12
* Bug fixes: till 2015-12-11
* Security fixes: till 2016-12-11
# 0.5.x
* Release date: 2013-12-01
* Bug fixes: till 2015-03-11
* Security fixes: till 2015-12-11
UPGRADE.md 0000644 00000014376 13721511157 0006173 0 ustar 00 ---
title: Upgrade
---
This is a list of backwards compatibility (BC) breaks introduced in ProxyManager:
# 2.0.0
* PHP `~7.0` is now required to use ProxyManager
* HHVM compatibility is not guaranteed, as HHVM is not yet PHP 7 compliant
* All classes and interfaces now use [strict scalar type hints](http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration).
If you extended or implemented anything from the `ProxyManager\` namespace, you probably need to change
that code to adapt it to the new signature.
* All classes and interfaces now use [return type declarations](http://php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration).
If you extended or implemented anything from the `ProxyManager\` namespace, you probably need to change
that code to adapt it to the new signature.
* ProxyManager will no longer write proxies to disk by default:
the [`EvaluatingGeneratorStrategy`](src/GeneratorStrategy/EvaluatingGeneratorStrategy.php) is used instead.
If you still want ProxyManager to write files to disk, please refer to the [tuning for production docs](docs/tuning-for-production.md)
* Ghost objects were entirely rewritten, for better support and improved performance. Lazy-loading is not
triggered by public API access, but by property access (private and public). While this is not really a BC
break, you are encouraged to check your applications if you rely on [ghost objects](docs/lazy-loading-ghost-object.md).
* If ProxyManager can't find a proxy, it will now automatically attempt to auto-generate it, regardless of
the settings passed to it.
* `ProxyManager\Configuration#setAutoGenerateProxies()` was removed. Please look for calls to this method and
remove them.
* Private properties are now also correctly handled by ProxyManager: accessing proxy state via friend classes
(protected or private scope) does not require any particular workarounds anymore.
* `ProxyManager\Version::VERSION` was removed. Please use `ProxyManager\Version::getVersion()` instead.
* PHP 4 style constructors are no longer supported
# 1.0.0
`1.0.0` is be fully compatible with `0.5.0`.
# 0.5.0
* The Generated Hydrator has been removed - it is now available as a separate project
at [Ocramius/GeneratedHydrator](https://github.com/Ocramius/GeneratedHydrator) [#65](https://github.com/Ocramius/ProxyManager/pull/65)
* When having a `public function __get($name)` defined (by-val) and public properties, it won't be possible to get public
properties by-ref while initializing the object. Either drop `__get()` or implement
a by-ref `& __get()` [#126](https://github.com/Ocramius/ProxyManager/pull/126)
* Proxies are now being always auto-generated if they could not be autoloaded by a factory. The methods
[`ProxyManager\Configuration#setAutoGenerateProxies()`](https://github.com/Ocramius/ProxyManager/blob/0.5.0-BETA2/src/ProxyManager/Configuration.php#L67)
and [`ProxyManager\Configuration#doesAutoGenerateProxies()`](https://github.com/Ocramius/ProxyManager/blob/0.5.0-BETA2/src/ProxyManager/Configuration.php#L75)
are now no-op and deprecated, and will be removed in the next minor
version [#87](https://github.com/Ocramius/ProxyManager/pull/87) [#90](https://github.com/Ocramius/ProxyManager/pull/90)
* Proxy public properties defaults are now set before initialization [#116](https://github.com/Ocramius/ProxyManager/pull/116) [#122](https://github.com/Ocramius/ProxyManager/pull/122)
# 0.4.0
* An optional parameter `$options` was introduced
in [`ProxyManager\Inflector\ClassNameInflectorInterface#getProxyClassName($className, array $options = array())`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Inflector/ClassNameInflectorInterface.php)
parametrize the generated class name as of [#10](https://github.com/Ocramius/ProxyManager/pull/10)
and [#59](https://github.com/Ocramius/ProxyManager/pull/59)
* Generated hydrators no longer have constructor arguments. Any required reflection instantiation is now dealt with
in the hydrator internally as of [#63](https://github.com/Ocramius/ProxyManager/pull/63)
# 0.3.4
* Interface names are also supported for proxy generation as of [#40](https://github.com/Ocramius/ProxyManager/pull/40)
# 0.3.3
* [Generated hydrators](https://github.com/Ocramius/ProxyManager/tree/master/docs/generated-hydrator.md) were introduced
# 0.3.2
* An additional (optional) [by-ref parameter was added](https://github.com/Ocramius/ProxyManager/pull/31)
to the lazy loading proxies' initializer to allow unsetting the initializer with less overhead.
# 0.3.0
* Dependency to [jms/cg](https://github.com/schmittjoh/cg-library) removed
* Moved code generation logic to [`Zend\Code`](https://github.com/zendframework/zf2)
* Added method [`ProxyManager\Inflector\ClassNameInflectorInterface#isProxyClassName($className)`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Inflector/ClassNameInflectorInterface.php)
* The constructor of [`ProxyManager\Autoloader\Autoloader`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Autoloader/Autoloader.php)
changed from `__construct(\ProxyManager\FileLocator\FileLocatorInterface $fileLocator)` to
`__construct(\ProxyManager\FileLocator\FileLocatorInterface $fileLocator, \ProxyManager\Inflector\ClassNameInflectorInterface $classNameInflector)`
* Classes implementing `CG\Core\GeneratorStrategyInterface` now implement
[`ProxyManager\GeneratorStrategy\GeneratorStrategyInterface`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/GeneratorStrategy/GeneratorStrategyInterface.php)
instead
* All code generation logic has been replaced - If you wrote any logic based on `ProxyManager\ProxyGenerator`, you will
have to rewrite it
# 0.2.0
* The signature of initializers to be used with proxies implementing
[`ProxyManager\Proxy\LazyLoadingInterface`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Proxy/LazyLoadingInterface.php)
changed from:
```php
$initializer = function ($proxy, & $wrappedObject, $method, $parameters) {};
```
to
```php
$initializer = function (& $wrappedObject, $proxy, $method, $parameters) {};
```
Only the order of parameters passed to the closures has been changed.
composer.json 0000644 00000004650 13721511157 0007276 0 ustar 00 {
"name": "ocramius/proxy-manager",
"description": "A library providing utilities to generate, instantiate and generally operate with Object Proxies",
"type": "library",
"license": "MIT",
"homepage": "https://github.com/Ocramius/ProxyManager",
"keywords": [
"proxy",
"proxy pattern",
"service proxies",
"lazy loading",
"aop"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "http://ocramius.github.io/"
}
],
"require": {
"php": "~7.4.1",
"laminas/laminas-code": "^3.4.1",
"composer-runtime-api": "^2.0.0",
"webimpress/safe-writer": "^2.0.1"
},
"conflict": {
"zendframework/zend-stdlib": "<3.2.1",
"laminas/laminas-stdlib": "<3.2.1",
"doctrine/annotations": "<1.6.1"
},
"require-dev": {
"ext-phar": "*",
"phpunit/phpunit": "^9.2.5",
"squizlabs/php_codesniffer": "^3.5.5",
"slevomat/coding-standard": "^6.3.10",
"doctrine/coding-standard": "^8.1.0",
"nikic/php-parser": "^4.6.0",
"phpbench/phpbench": "^0.17.1",
"infection/infection": "^0.16.4",
"vimeo/psalm": "^3.12.2",
"codelicia/xulieta": "^0.1.2"
},
"suggest": {
"ocramius/generated-hydrator": "To have very fast object to array to object conversion for ghost objects",
"laminas/laminas-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)",
"laminas/laminas-json": "To have the JsonRpc adapter (Remote Object feature)",
"laminas/laminas-soap": "To have the Soap adapter (Remote Object feature)"
},
"autoload": {
"psr-4": {
"ProxyManager\\": "src/ProxyManager"
}
},
"autoload-dev": {
"psr-4": {
"ProxyManagerBench\\": "tests/ProxyManagerBench",
"ProxyManagerTest\\": "tests/ProxyManagerTest",
"ProxyManagerTestAsset\\": "tests/ProxyManagerTestAsset",
"Laminas\\Server\\": "tests/Stubbed/Laminas/Server"
}
},
"extra": {
"branch-alias": {
"dev-master": "3.0.x-dev"
}
}
}
composer.lock 0000644 00000662207 13721511157 0007265 0 ustar 00 {
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "a5bd4f77d43eaad609b66fd4f3edc446",
"packages": [
{
"name": "laminas/laminas-code",
"version": "3.4.1",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-code.git",
"reference": "1cb8f203389ab1482bf89c0e70a04849bacd7766"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-code/zipball/1cb8f203389ab1482bf89c0e70a04849bacd7766",
"reference": "1cb8f203389ab1482bf89c0e70a04849bacd7766",
"shasum": ""
},
"require": {
"laminas/laminas-eventmanager": "^2.6 || ^3.0",
"laminas/laminas-zendframework-bridge": "^1.0",
"php": "^7.1"
},
"conflict": {
"phpspec/prophecy": "<1.9.0"
},
"replace": {
"zendframework/zend-code": "self.version"
},
"require-dev": {
"doctrine/annotations": "^1.7",
"ext-phar": "*",
"laminas/laminas-coding-standard": "^1.0",
"laminas/laminas-stdlib": "^2.7 || ^3.0",
"phpunit/phpunit": "^7.5.16 || ^8.4"
},
"suggest": {
"doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features",
"laminas/laminas-stdlib": "Laminas\\Stdlib component"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.4.x-dev",
"dev-develop": "3.5.x-dev",
"dev-dev-4.0": "4.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Laminas\\Code\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Extensions to the PHP Reflection API, static code scanning, and code generation",
"homepage": "https://laminas.dev",
"keywords": [
"code",
"laminas"
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-code/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-code/issues",
"rss": "https://github.com/laminas/laminas-code/releases.atom",
"source": "https://github.com/laminas/laminas-code"
},
"time": "2019-12-31T16:28:24+00:00"
},
{
"name": "laminas/laminas-eventmanager",
"version": "3.2.1",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-eventmanager.git",
"reference": "ce4dc0bdf3b14b7f9815775af9dfee80a63b4748"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-eventmanager/zipball/ce4dc0bdf3b14b7f9815775af9dfee80a63b4748",
"reference": "ce4dc0bdf3b14b7f9815775af9dfee80a63b4748",
"shasum": ""
},
"require": {
"laminas/laminas-zendframework-bridge": "^1.0",
"php": "^5.6 || ^7.0"
},
"replace": {
"zendframework/zend-eventmanager": "self.version"
},
"require-dev": {
"athletic/athletic": "^0.1",
"container-interop/container-interop": "^1.1.0",
"laminas/laminas-coding-standard": "~1.0.0",
"laminas/laminas-stdlib": "^2.7.3 || ^3.0",
"phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2"
},
"suggest": {
"container-interop/container-interop": "^1.1.0, to use the lazy listeners feature",
"laminas/laminas-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev",
"dev-develop": "3.3-dev"
}
},
"autoload": {
"psr-4": {
"Laminas\\EventManager\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Trigger and listen to events within a PHP application",
"homepage": "https://laminas.dev",
"keywords": [
"event",
"eventmanager",
"events",
"laminas"
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-eventmanager/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-eventmanager/issues",
"rss": "https://github.com/laminas/laminas-eventmanager/releases.atom",
"source": "https://github.com/laminas/laminas-eventmanager"
},
"time": "2019-12-31T16:44:52+00:00"
},
{
"name": "laminas/laminas-zendframework-bridge",
"version": "1.0.4",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-zendframework-bridge.git",
"reference": "fcd87520e4943d968557803919523772475e8ea3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/fcd87520e4943d968557803919523772475e8ea3",
"reference": "fcd87520e4943d968557803919523772475e8ea3",
"shasum": ""
},
"require": {
"php": "^5.6 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev",
"dev-develop": "1.1.x-dev"
},
"laminas": {
"module": "Laminas\\ZendFrameworkBridge"
}
},
"autoload": {
"files": [
"src/autoload.php"
],
"psr-4": {
"Laminas\\ZendFrameworkBridge\\": "src//"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Alias legacy ZF class names to Laminas Project equivalents.",
"keywords": [
"ZendFramework",
"autoloading",
"laminas",
"zf"
],
"support": {
"forum": "https://discourse.laminas.dev/",
"issues": "https://github.com/laminas/laminas-zendframework-bridge/issues",
"rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom",
"source": "https://github.com/laminas/laminas-zendframework-bridge"
},
"funding": [
{
"url": "https://funding.communitybridge.org/projects/laminas-project",
"type": "community_bridge"
}
],
"time": "2020-05-20T16:45:56+00:00"
},
{
"name": "webimpress/safe-writer",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/webimpress/safe-writer.git",
"reference": "d6e879960febb307c112538997316371f1e95b12"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webimpress/safe-writer/zipball/d6e879960febb307c112538997316371f1e95b12",
"reference": "d6e879960febb307c112538997316371f1e95b12",
"shasum": ""
},
"require": {
"php": "^7.2"
},
"require-dev": {
"phpunit/phpunit": "^8.5.2 || ^9.0.1",
"webimpress/coding-standard": "^1.1.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev",
"dev-develop": "2.1.x-dev",
"dev-release-1.0": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Webimpress\\SafeWriter\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"description": "Tool to write files safely, to avoid race conditions",
"keywords": [
"concurrent write",
"file writer",
"race condition",
"safe writer",
"webimpress"
],
"support": {
"issues": "https://github.com/webimpress/safe-writer/issues",
"source": "https://github.com/webimpress/safe-writer/tree/2.0.1"
},
"funding": [
{
"url": "https://github.com/michalbundyra",
"type": "github"
}
],
"time": "2020-03-21T15:49:08+00:00"
}
],
"packages-dev": [
{
"name": "amphp/amp",
"version": "v2.4.4",
"source": {
"type": "git",
"url": "https://github.com/amphp/amp.git",
"reference": "1e58d53e4af390efc7813e36cd215bd82cba4b06"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/amp/zipball/1e58d53e4af390efc7813e36cd215bd82cba4b06",
"reference": "1e58d53e4af390efc7813e36cd215bd82cba4b06",
"shasum": ""
},
"require": {
"php": ">=7"
},
"require-dev": {
"amphp/php-cs-fixer-config": "dev-master",
"amphp/phpunit-util": "^1",
"ext-json": "*",
"jetbrains/phpstorm-stubs": "^2019.3",
"phpunit/phpunit": "^6.0.9 | ^7",
"react/promise": "^2",
"vimeo/psalm": "^3.11@dev"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"Amp\\": "lib"
},
"files": [
"lib/functions.php",
"lib/Internal/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Daniel Lowrey",
"email": "rdlowrey@php.net"
},
{
"name": "Aaron Piotrowski",
"email": "aaron@trowski.com"
},
{
"name": "Bob Weinand",
"email": "bobwei9@hotmail.com"
},
{
"name": "Niklas Keller",
"email": "me@kelunik.com"
}
],
"description": "A non-blocking concurrency framework for PHP applications.",
"homepage": "http://amphp.org/amp",
"keywords": [
"async",
"asynchronous",
"awaitable",
"concurrency",
"event",
"event-loop",
"future",
"non-blocking",
"promise"
],
"support": {
"irc": "irc://irc.freenode.org/amphp",
"issues": "https://github.com/amphp/amp/issues",
"source": "https://github.com/amphp/amp/tree/v2.4.4"
},
"time": "2020-04-30T04:54:50+00:00"
},
{
"name": "amphp/byte-stream",
"version": "v1.7.3",
"source": {
"type": "git",
"url": "https://github.com/amphp/byte-stream.git",
"reference": "b867505edb79dda8f253ca3c3a2bbadae4b16592"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/amphp/byte-stream/zipball/b867505edb79dda8f253ca3c3a2bbadae4b16592",
"reference": "b867505edb79dda8f253ca3c3a2bbadae4b16592",
"shasum": ""
},
"require": {
"amphp/amp": "^2"
},
"require-dev": {
"amphp/php-cs-fixer-config": "dev-master",
"amphp/phpunit-util": "^1",
"friendsofphp/php-cs-fixer": "^2.3",
"jetbrains/phpstorm-stubs": "^2019.3",
"phpunit/phpunit": "^6 || ^7 || ^8",
"vimeo/psalm": "^3.9@dev"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Amp\\ByteStream\\": "lib"
},
"files": [
"lib/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Aaron Piotrowski",
"email": "aaron@trowski.com"
},
{
"name": "Niklas Keller",
"email": "me@kelunik.com"
}
],
"description": "A stream abstraction to make working with non-blocking I/O simple.",
"homepage": "http://amphp.org/byte-stream",
"keywords": [
"amp",
"amphp",
"async",
"io",
"non-blocking",
"stream"
],
"support": {
"irc": "irc://irc.freenode.org/amphp",
"issues": "https://github.com/amphp/byte-stream/issues",
"source": "https://github.com/amphp/byte-stream/tree/v1.7.3"
},
"time": "2020-04-04T16:56:54+00:00"
},
{
"name": "beberlei/assert",
"version": "v3.2.7",
"source": {
"type": "git",
"url": "https://github.com/beberlei/assert.git",
"reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/beberlei/assert/zipball/d63a6943fc4fd1a2aedb65994e3548715105abcf",
"reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-simplexml": "*",
"php": "^7"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "*",
"phpstan/phpstan-shim": "*",
"phpunit/phpunit": ">=6.0.0 <8"
},
"suggest": {
"ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles"
},
"type": "library",
"autoload": {
"psr-4": {
"Assert\\": "lib/Assert"
},
"files": [
"lib/Assert/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de",
"role": "Lead Developer"
},
{
"name": "Richard Quadling",
"email": "rquadling@gmail.com",
"role": "Collaborator"
}
],
"description": "Thin assertion library for input validation in business models.",
"keywords": [
"assert",
"assertion",
"validation"
],
"support": {
"issues": "https://github.com/beberlei/assert/issues",
"source": "https://github.com/beberlei/assert/tree/v3"
},
"time": "2019-12-19T17:51:41+00:00"
},
{
"name": "codelicia/xulieta",
"version": "0.1.2",
"source": {
"type": "git",
"url": "https://github.com/codelicia/xulieta.git",
"reference": "288a2358e9315d9ddbdb74a68b3bf9b65c1670d5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/codelicia/xulieta/zipball/288a2358e9315d9ddbdb74a68b3bf9b65c1670d5",
"reference": "288a2358e9315d9ddbdb74a68b3bf9b65c1670d5",
"shasum": ""
},
"require": {
"beberlei/assert": "^3.2",
"doctrine/rst-parser": "^0.1.0",
"nikic/php-parser": "^4.3",
"ocramius/package-versions": "^1.5",
"php": ">=7.4",
"symfony/config": "^5.0",
"symfony/console": "^5.0",
"symfony/finder": "^5.0",
"symfony/process": "^5.0",
"webmozart/assert": "^1.7"
},
"require-dev": {
"doctrine/coding-standard": "^7.0.2",
"phpunit/phpunit": "^9.0",
"roave/security-advisories": "dev-master",
"staabm/annotate-pull-request-from-checkstyle": "^1.1",
"vimeo/psalm": "^3.9"
},
"bin": [
"bin/xulieta"
],
"type": "library",
"autoload": {
"psr-4": {
"Codelicia\\Xulieta\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jefersson Nathan",
"email": "malukenho.dev@gmail.com"
},
{
"name": "Alexandre Eher",
"email": "alexandre@eher.com.br"
}
],
"description": "Xulieta is a light php binary that lint documentation snippets",
"homepage": "https://github.com/codelicia/xulieta",
"keywords": [
"check documentation",
"documentation",
"linter"
],
"support": {
"issues": "https://github.com/codelicia/xulieta/issues",
"source": "https://github.com/codelicia/xulieta/tree/master"
},
"time": "2020-05-15T21:09:34+00:00"
},
{
"name": "composer/semver",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "3426bd5efa8a12d230824536c42a8a4ad30b7940"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3426bd5efa8a12d230824536c42a8a4ad30b7940",
"reference": "3426bd5efa8a12d230824536c42a8a4ad30b7940",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^0.12.19",
"symfony/phpunit-bridge": "^4.2 || ^5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Semver\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
},
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com",
"homepage": "http://robbast.nl"
}
],
"description": "Semver library that offers utilities, version constraint parsing and validation.",
"keywords": [
"semantic",
"semver",
"validation",
"versioning"
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.0.0"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2020-05-26T18:22:04+00:00"
},
{
"name": "composer/xdebug-handler",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
"reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51",
"reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0",
"psr/log": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
},
"type": "library",
"autoload": {
"psr-4": {
"Composer\\XdebugHandler\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "John Stevenson",
"email": "john-stevenson@blueyonder.co.uk"
}
],
"description": "Restarts a process without Xdebug.",
"keywords": [
"Xdebug",
"performance"
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/xdebug-handler/issues",
"source": "https://github.com/composer/xdebug-handler/tree/1.4.2"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2020-06-04T11:16:35+00:00"
},
{
"name": "dealerdirect/phpcodesniffer-composer-installer",
"version": "v0.7.0",
"source": {
"type": "git",
"url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
"reference": "e8d808670b8f882188368faaf1144448c169c0b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e8d808670b8f882188368faaf1144448c169c0b7",
"reference": "e8d808670b8f882188368faaf1144448c169c0b7",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0 || ^2.0",
"php": ">=5.3",
"squizlabs/php_codesniffer": "^2 || ^3 || 4.0.x-dev"
},
"require-dev": {
"composer/composer": "*",
"phpcompatibility/php-compatibility": "^9.0",
"sensiolabs/security-checker": "^4.1.0"
},
"type": "composer-plugin",
"extra": {
"class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
},
"autoload": {
"psr-4": {
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Franck Nijhof",
"email": "franck.nijhof@dealerdirect.com",
"homepage": "http://www.frenck.nl",
"role": "Developer / IT Manager"
}
],
"description": "PHP_CodeSniffer Standards Composer Installer Plugin",
"homepage": "http://www.dealerdirect.com",
"keywords": [
"PHPCodeSniffer",
"PHP_CodeSniffer",
"code quality",
"codesniffer",
"composer",
"installer",
"phpcs",
"plugin",
"qa",
"quality",
"standard",
"standards",
"style guide",
"stylecheck",
"tests"
],
"support": {
"issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues",
"source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer"
},
"time": "2020-06-25T14:57:39+00:00"
},
{
"name": "doctrine/annotations",
"version": "1.10.3",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/5db60a4969eba0e0c197a19c077780aadbc43c5d",
"reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d",
"shasum": ""
},
"require": {
"doctrine/lexer": "1.*",
"ext-tokenizer": "*",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/cache": "1.*",
"phpunit/phpunit": "^7.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Docblock Annotations Parser",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"docblock",
"parser"
],
"support": {
"issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/1.10.x"
},
"time": "2020-05-25T17:24:27+00:00"
},
{
"name": "doctrine/coding-standard",
"version": "8.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/coding-standard.git",
"reference": "637003febec655f1b27f4301b44bf2264be57434"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/coding-standard/zipball/637003febec655f1b27f4301b44bf2264be57434",
"reference": "637003febec655f1b27f4301b44bf2264be57434",
"shasum": ""
},
"require": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7",
"php": "^7.2 || ^8.0",
"slevomat/coding-standard": "^6.3.9",
"squizlabs/php_codesniffer": "^3.5.5"
},
"type": "phpcodesniffer-standard",
"extra": {
"branch-alias": {
"dev-master": "7.0.x-dev"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Steve Müller",
"email": "st.mueller@dzh-online.de"
}
],
"description": "The Doctrine Coding Standard is a set of PHPCS rules applied to all Doctrine projects.",
"homepage": "https://www.doctrine-project.org/projects/coding-standard.html",
"keywords": [
"checks",
"code",
"coding",
"cs",
"doctrine",
"rules",
"sniffer",
"sniffs",
"standard",
"style"
],
"support": {
"issues": "https://github.com/doctrine/coding-standard/issues",
"source": "https://github.com/doctrine/coding-standard/tree/8.1.x"
},
"time": "2020-07-05T20:35:22+00:00"
},
{
"name": "doctrine/event-manager",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/event-manager.git",
"reference": "629572819973f13486371cb611386eb17851e85c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/629572819973f13486371cb611386eb17851e85c",
"reference": "629572819973f13486371cb611386eb17851e85c",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"conflict": {
"doctrine/common": "<2.9@dev"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\": "lib/Doctrine/Common"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
},
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
"homepage": "https://www.doctrine-project.org/projects/event-manager.html",
"keywords": [
"event",
"event dispatcher",
"event manager",
"event system",
"events"
],
"support": {
"issues": "https://github.com/doctrine/event-manager/issues",
"source": "https://github.com/doctrine/event-manager/tree/1.1.0"
},
"time": "2019-11-10T09:48:07+00:00"
},
{
"name": "doctrine/instantiator",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "f350df0268e904597e3bd9c4685c53e0e333feea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea",
"reference": "f350df0268e904597e3bd9c4685c53e0e333feea",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"ext-pdo": "*",
"ext-phar": "*",
"phpbench/phpbench": "^0.13",
"phpstan/phpstan-phpunit": "^0.11",
"phpstan/phpstan-shim": "^0.11",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "http://ocramius.github.com/"
}
],
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
"homepage": "https://www.doctrine-project.org/projects/instantiator.html",
"keywords": [
"constructor",
"instantiate"
],
"support": {
"issues": "https://github.com/doctrine/instantiator/issues",
"source": "https://github.com/doctrine/instantiator/tree/1.3.x"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
"type": "tidelift"
}
],
"time": "2020-05-29T17:27:14+00:00"
},
{
"name": "doctrine/lexer",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "e864bbf5904cb8f5bb334f99209b48018522f042"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042",
"reference": "e864bbf5904cb8f5bb334f99209b48018522f042",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"phpstan/phpstan": "^0.11.8",
"phpunit/phpunit": "^8.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
"keywords": [
"annotations",
"docblock",
"lexer",
"parser",
"php"
],
"support": {
"issues": "https://github.com/doctrine/lexer/issues",
"source": "https://github.com/doctrine/lexer/tree/1.2.1"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
"type": "tidelift"
}
],
"time": "2020-05-25T17:44:05+00:00"
},
{
"name": "doctrine/rst-parser",
"version": "0.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/rst-parser.git",
"reference": "49ea41cf15b93c4ac493df3f05c49999ef661cd4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/rst-parser/zipball/49ea41cf15b93c4ac493df3f05c49999ef661cd4",
"reference": "49ea41cf15b93c4ac493df3f05c49999ef661cd4",
"shasum": ""
},
"require": {
"doctrine/event-manager": "^1.0",
"php": "^7.1",
"symfony/filesystem": "^4.1",
"twig/twig": "^2.5"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"gajus/dindent": "^2.0.2",
"phpstan/phpstan": "^0.10",
"phpstan/phpstan-deprecation-rules": "^0.10",
"phpstan/phpstan-phpunit": "^0.10",
"phpstan/phpstan-strict-rules": "^0.10",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\RST\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Grégoire Passault",
"email": "g.passault@gmail.com",
"homepage": "http://www.gregwar.com/"
},
{
"name": "Jonathan H. Wage",
"email": "jonwage@gmail.com",
"homepage": "https://jwage.com"
}
],
"description": "PHP library to parse reStructuredText documents and generate HTML or LaTeX documents.",
"homepage": "https://github.com/doctrine/rst-parser",
"keywords": [
"html",
"latex",
"markup",
"parser",
"reStructuredText",
"rst"
],
"support": {
"issues": "https://github.com/doctrine/rst-parser/issues",
"source": "https://github.com/doctrine/rst-parser/tree/0.1.0"
},
"time": "2019-04-15T19:55:14+00:00"
},
{
"name": "felixfbecker/advanced-json-rpc",
"version": "v3.1.1",
"source": {
"type": "git",
"url": "https://github.com/felixfbecker/php-advanced-json-rpc.git",
"reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/0ed363f8de17d284d479ec813c9ad3f6834b5c40",
"reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40",
"shasum": ""
},
"require": {
"netresearch/jsonmapper": "^1.0 || ^2.0",
"php": ">=7.0",
"phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0.0"
},
"type": "library",
"autoload": {
"psr-4": {
"AdvancedJsonRpc\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Felix Becker",
"email": "felix.b@outlook.com"
}
],
"description": "A more advanced JSONRPC implementation",
"support": {
"issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues",
"source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/master"
},
"time": "2020-03-11T15:21:41+00:00"
},
{
"name": "felixfbecker/language-server-protocol",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/felixfbecker/php-language-server-protocol.git",
"reference": "378801f6139bb74ac215d81cca1272af61df9a9f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/378801f6139bb74ac215d81cca1272af61df9a9f",
"reference": "378801f6139bb74ac215d81cca1272af61df9a9f",
"shasum": ""
},
"require": {
"php": "^7.0"
},
"require-dev": {
"phpstan/phpstan": "*",
"phpunit/phpunit": "^6.3",
"squizlabs/php_codesniffer": "^3.1"
},
"type": "library",
"autoload": {
"psr-4": {
"LanguageServerProtocol\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Felix Becker",
"email": "felix.b@outlook.com"
}
],
"description": "PHP classes for the Language Server Protocol",
"keywords": [
"language",
"microsoft",
"php",
"server"
],
"support": {
"issues": "https://github.com/felixfbecker/php-language-server-protocol/issues",
"source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.4.0"
},
"time": "2019-06-23T21:03:50+00:00"
},
{
"name": "infection/abstract-testframework-adapter",
"version": "0.3.0",
"source": {
"type": "git",
"url": "https://github.com/infection/abstract-testframework-adapter.git",
"reference": "f3ec6fc4beb6377b72d8106f5ff329dffd51ca8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/infection/abstract-testframework-adapter/zipball/f3ec6fc4beb6377b72d8106f5ff329dffd51ca8a",
"reference": "f3ec6fc4beb6377b72d8106f5ff329dffd51ca8a",
"shasum": ""
},
"require": {
"php": "^7.3"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Infection\\AbstractTestFramework\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Maks Rafalko",
"email": "maks.rafalko@gmail.com"
}
],
"description": "Abstract Test Framework Adapter for Infection",
"support": {
"issues": "https://github.com/infection/abstract-testframework-adapter/issues",
"source": "https://github.com/infection/abstract-testframework-adapter/tree/master"
},
"time": "2020-03-14T07:20:06+00:00"
},
{
"name": "infection/extension-installer",
"version": "0.1.1",
"source": {
"type": "git",
"url": "https://github.com/infection/extension-installer.git",
"reference": "ff30c0adffcdbc747c96adf92382ccbe271d0afd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/infection/extension-installer/zipball/ff30c0adffcdbc747c96adf92382ccbe271d0afd",
"reference": "ff30c0adffcdbc747c96adf92382ccbe271d0afd",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.1 || ^2.0"
},
"require-dev": {
"composer/composer": "^1.9",
"friendsofphp/php-cs-fixer": "^2.16",
"infection/infection": "^0.15.2",
"php-coveralls/php-coveralls": "^2.2",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12.10",
"phpstan/phpstan-phpunit": "^0.12.6",
"phpstan/phpstan-strict-rules": "^0.12.2",
"phpstan/phpstan-webmozart-assert": "^0.12.2",
"phpunit/phpunit": "^8.5",
"vimeo/psalm": "^3.8"
},
"type": "composer-plugin",
"extra": {
"class": "Infection\\ExtensionInstaller\\Plugin"
},
"autoload": {
"psr-4": {
"Infection\\ExtensionInstaller\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Maks Rafalko",
"email": "maks.rafalko@gmail.com"
}
],
"description": "Infection Extension Installer",
"support": {
"issues": "https://github.com/infection/extension-installer/issues",
"source": "https://github.com/infection/extension-installer/tree/0.1.1"
},
"time": "2020-04-25T22:40:05+00:00"
},
{
"name": "infection/include-interceptor",
"version": "0.2.3",
"source": {
"type": "git",
"url": "https://github.com/infection/include-interceptor.git",
"reference": "07d20c33a6c0624b8636adf25ddca7e9e19a5dc9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/infection/include-interceptor/zipball/07d20c33a6c0624b8636adf25ddca7e9e19a5dc9",
"reference": "07d20c33a6c0624b8636adf25ddca7e9e19a5dc9",
"shasum": ""
},
"require-dev": {
"phpunit/phpunit": "^8.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Infection\\StreamWrapper\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Maks Rafalko",
"email": "maks.rafalko@gmail.com"
}
],
"description": "Stream Wrapper: Include Interceptor. Allows to replace included (autoloaded) file with another one.",
"support": {
"issues": "https://github.com/infection/include-interceptor/issues",
"source": "https://github.com/infection/include-interceptor/tree/0.2.3"
},
"time": "2020-01-27T10:28:21+00:00"
},
{
"name": "infection/infection",
"version": "0.16.4",
"source": {
"type": "git",
"url": "https://github.com/infection/infection.git",
"reference": "c1ef0b16b3e8d171f10ba8bfe8b6c93d482a68b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/infection/infection/zipball/c1ef0b16b3e8d171f10ba8bfe8b6c93d482a68b4",
"reference": "c1ef0b16b3e8d171f10ba8bfe8b6c93d482a68b4",
"shasum": ""
},
"require": {
"composer/xdebug-handler": "^1.3.3",
"ext-dom": "*",
"ext-json": "*",
"ext-libxml": "*",
"infection/abstract-testframework-adapter": "^0.3.0",
"infection/extension-installer": "^0.1.0",
"infection/include-interceptor": "^0.2.2",
"justinrainbow/json-schema": "^5.2",
"nikic/php-parser": "^4.2.2",
"ocramius/package-versions": "^1.2",
"ondram/ci-detector": "^3.3.0",
"php": "^7.3",
"sanmai/pipeline": "^3.1",
"sebastian/diff": "^3.0.2 || ^4.0",
"seld/jsonlint": "^1.7",
"symfony/console": "^3.4.29 || ^4.0 || ^5.0",
"symfony/filesystem": "^3.4.29 || ^4.0 || ^5.0",
"symfony/finder": "^3.4.29 || ^4.0 || ^5.0",
"symfony/process": "^3.4.29 || ^4.0 || ^5.0",
"thecodingmachine/safe": "^1.0",
"webmozart/assert": "^1.3",
"webmozart/path-util": "^2.3"
},
"conflict": {
"symfony/console": "=4.1.5"
},
"require-dev": {
"ext-simplexml": "*",
"helmich/phpunit-json-assert": "^3.0",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12.8",
"phpstan/phpstan-phpunit": "^0.12.6",
"phpstan/phpstan-webmozart-assert": "^0.12.2",
"phpunit/phpunit": "^8.2.5 <8.4",
"symfony/phpunit-bridge": "^4.3.4 || ^5.0",
"symfony/yaml": "^5.0",
"thecodingmachine/phpstan-safe-rule": "^1.0"
},
"bin": [
"bin/infection"
],
"type": "library",
"autoload": {
"psr-4": {
"Infection\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Maks Rafalko",
"email": "maks.rafalko@gmail.com",
"homepage": "https://twitter.com/maks_rafalko"
},
{
"name": "Oleg Zhulnev",
"homepage": "https://github.com/sidz"
},
{
"name": "Gert de Pagter",
"homepage": "https://github.com/BackEndTea"
},
{
"name": "Théo FIDRY",
"email": "theo.fidry@gmail.com",
"homepage": "https://twitter.com/tfidry"
},
{
"name": "Alexey Kopytko",
"email": "alexey@kopytko.com",
"homepage": "https://www.alexeykopytko.com"
},
{
"name": "Andreas Möller",
"email": "am@localheinz.com",
"homepage": "https://localheinz.com"
}
],
"description": "Infection is a Mutation Testing framework for PHP. The mutation adequacy score can be used to measure the effectiveness of a test set in terms of its ability to detect faults.",
"keywords": [
"coverage",
"mutant",
"mutation framework",
"mutation testing",
"testing",
"unit testing"
],
"support": {
"issues": "https://github.com/infection/infection/issues",
"source": "https://github.com/infection/infection/tree/0.16"
},
"time": "2020-06-25T15:14:51+00:00"
},
{
"name": "justinrainbow/json-schema",
"version": "5.2.10",
"source": {
"type": "git",
"url": "https://github.com/justinrainbow/json-schema.git",
"reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b",
"reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1",
"json-schema/json-schema-test-suite": "1.2.0",
"phpunit/phpunit": "^4.8.35"
},
"bin": [
"bin/validate-json"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0.x-dev"
}
},
"autoload": {
"psr-4": {
"JsonSchema\\": "src/JsonSchema/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bruno Prieto Reis",
"email": "bruno.p.reis@gmail.com"
},
{
"name": "Justin Rainbow",
"email": "justin.rainbow@gmail.com"
},
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
},
{
"name": "Robert Schönthal",
"email": "seroscho@googlemail.com"
}
],
"description": "A library to validate a json schema.",
"homepage": "https://github.com/justinrainbow/json-schema",
"keywords": [
"json",
"schema"
],
"support": {
"issues": "https://github.com/justinrainbow/json-schema/issues",
"source": "https://github.com/justinrainbow/json-schema/tree/5.2.10"
},
"time": "2020-05-27T16:41:55+00:00"
},
{
"name": "lstrojny/functional-php",
"version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/lstrojny/functional-php.git",
"reference": "11610f50323519dd38bd7b527d6730e524e5eb58"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lstrojny/functional-php/zipball/11610f50323519dd38bd7b527d6730e524e5eb58",
"reference": "11610f50323519dd38bd7b527d6730e524e5eb58",
"shasum": ""
},
"require": {
"php": "~7"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.14",
"phpunit/phpunit": "~7",
"squizlabs/php_codesniffer": "~3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Functional\\": "src/Functional"
},
"files": [
"src/Functional/Ary.php",
"src/Functional/Average.php",
"src/Functional/ButLast.php",
"src/Functional/Capture.php",
"src/Functional/ConstFunction.php",
"src/Functional/CompareOn.php",
"src/Functional/CompareObjectHashOn.php",
"src/Functional/Compose.php",
"src/Functional/Concat.php",
"src/Functional/Contains.php",
"src/Functional/Converge.php",
"src/Functional/Curry.php",
"src/Functional/CurryN.php",
"src/Functional/Difference.php",
"src/Functional/DropFirst.php",
"src/Functional/DropLast.php",
"src/Functional/Each.php",
"src/Functional/Equal.php",
"src/Functional/ErrorToException.php",
"src/Functional/Every.php",
"src/Functional/False.php",
"src/Functional/Falsy.php",
"src/Functional/Filter.php",
"src/Functional/First.php",
"src/Functional/FirstIndexOf.php",
"src/Functional/FlatMap.php",
"src/Functional/Flatten.php",
"src/Functional/Flip.php",
"src/Functional/GreaterThan.php",
"src/Functional/GreaterThanOrEqual.php",
"src/Functional/Group.php",
"src/Functional/Head.php",
"src/Functional/Id.php",
"src/Functional/IfElse.php",
"src/Functional/Identical.php",
"src/Functional/IndexesOf.php",
"src/Functional/Intersperse.php",
"src/Functional/Invoke.php",
"src/Functional/InvokeFirst.php",
"src/Functional/InvokeIf.php",
"src/Functional/InvokeLast.php",
"src/Functional/Invoker.php",
"src/Functional/Last.php",
"src/Functional/LastIndexOf.php",
"src/Functional/LessThan.php",
"src/Functional/LessThanOrEqual.php",
"src/Functional/LexicographicCompare.php",
"src/Functional/Map.php",
"src/Functional/Match.php",
"src/Functional/Maximum.php",
"src/Functional/Memoize.php",
"src/Functional/Minimum.php",
"src/Functional/None.php",
"src/Functional/Noop.php",
"src/Functional/Not.php",
"src/Functional/OmitKeys.php",
"src/Functional/PartialAny.php",
"src/Functional/PartialLeft.php",
"src/Functional/PartialMethod.php",
"src/Functional/PartialRight.php",
"src/Functional/Partition.php",
"src/Functional/Pick.php",
"src/Functional/Pluck.php",
"src/Functional/Poll.php",
"src/Functional/Product.php",
"src/Functional/Ratio.php",
"src/Functional/ReduceLeft.php",
"src/Functional/ReduceRight.php",
"src/Functional/Reindex.php",
"src/Functional/Reject.php",
"src/Functional/Repeat.php",
"src/Functional/Retry.php",
"src/Functional/Select.php",
"src/Functional/SelectKeys.php",
"src/Functional/SequenceConstant.php",
"src/Functional/SequenceExponential.php",
"src/Functional/SequenceLinear.php",
"src/Functional/Some.php",
"src/Functional/Sort.php",
"src/Functional/Sum.php",
"src/Functional/SuppressError.php",
"src/Functional/Tap.php",
"src/Functional/Tail.php",
"src/Functional/TailRecursion.php",
"src/Functional/TakeLeft.php",
"src/Functional/TakeRight.php",
"src/Functional/True.php",
"src/Functional/Truthy.php",
"src/Functional/Unique.php",
"src/Functional/With.php",
"src/Functional/Zip.php",
"src/Functional/ZipAll.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Lars Strojny",
"email": "lstrojny@php.net",
"homepage": "http://usrportage.de"
},
{
"name": "Max Beutel",
"email": "nash12@gmail.com"
}
],
"description": "Functional primitives for PHP",
"keywords": [
"functional"
],
"support": {
"issues": "https://github.com/lstrojny/functional-php/issues",
"source": "https://github.com/lstrojny/functional-php/tree/master"
},
"time": "2020-06-16T09:17:22+00:00"
},
{
"name": "myclabs/deep-copy",
"version": "1.10.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
"reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"replace": {
"myclabs/deep-copy": "self.version"
},
"require-dev": {
"doctrine/collections": "^1.0",
"doctrine/common": "^2.6",
"phpunit/phpunit": "^7.1"
},
"type": "library",
"autoload": {
"psr-4": {
"DeepCopy\\": "src/DeepCopy/"
},
"files": [
"src/DeepCopy/deep_copy.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Create deep copies (clones) of your objects",
"keywords": [
"clone",
"copy",
"duplicate",
"object",
"object graph"
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.x"
},
"funding": [
{
"url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
"type": "tidelift"
}
],
"time": "2020-06-29T13:22:24+00:00"
},
{
"name": "netresearch/jsonmapper",
"version": "v2.1.0",
"source": {
"type": "git",
"url": "https://github.com/cweiske/jsonmapper.git",
"reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e",
"reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.6"
},
"require-dev": {
"phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0",
"squizlabs/php_codesniffer": "~3.5"
},
"type": "library",
"autoload": {
"psr-0": {
"JsonMapper": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"OSL-3.0"
],
"authors": [
{
"name": "Christian Weiske",
"email": "cweiske@cweiske.de",
"homepage": "http://github.com/cweiske/jsonmapper/",
"role": "Developer"
}
],
"description": "Map nested JSON structures onto PHP classes",
"support": {
"email": "cweiske@cweiske.de",
"issues": "https://github.com/cweiske/jsonmapper/issues",
"source": "https://github.com/cweiske/jsonmapper/tree/master"
},
"time": "2020-04-16T18:48:43+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.6.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "c346bbfafe2ff60680258b631afb730d186ed864"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c346bbfafe2ff60680258b631afb730d186ed864",
"reference": "c346bbfafe2ff60680258b631afb730d186ed864",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=7.0"
},
"require-dev": {
"ircmaxell/php-yacc": "0.0.5",
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0"
},
"bin": [
"bin/php-parse"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.3-dev"
}
},
"autoload": {
"psr-4": {
"PhpParser\\": "lib/PhpParser"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov"
}
],
"description": "A PHP parser written in PHP",
"keywords": [
"parser",
"php"
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.6.0"
},
"time": "2020-07-02T17:12:47+00:00"
},
{
"name": "ocramius/package-versions",
"version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/Ocramius/PackageVersions.git",
"reference": "80f88b35ff45a0fdccf852d4788bb79bb67c3817"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/80f88b35ff45a0fdccf852d4788bb79bb67c3817",
"reference": "80f88b35ff45a0fdccf852d4788bb79bb67c3817",
"shasum": ""
},
"require": {
"composer-plugin-api": "^2.0.0",
"composer-runtime-api": "^2.0.0",
"php": "^7.4.7"
},
"require-dev": {
"composer/composer": "^2.0.0@dev",
"doctrine/coding-standard": "^8.1.0",
"ext-zip": "^1.15.0",
"infection/infection": "^0.16.4",
"phpunit/phpunit": "^9.1.5",
"vimeo/psalm": "^3.12.2"
},
"type": "composer-plugin",
"extra": {
"class": "PackageVersions\\Installer",
"branch-alias": {
"dev-master": "1.99.x-dev"
}
},
"autoload": {
"psr-4": {
"PackageVersions\\": "src/PackageVersions"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
"support": {
"issues": "https://github.com/Ocramius/PackageVersions/issues",
"source": "https://github.com/Ocramius/PackageVersions/tree/1.10.0"
},
"funding": [
{
"url": "https://github.com/Ocramius",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/ocramius/package-versions",
"type": "tidelift"
}
],
"time": "2020-07-11T19:45:58+00:00"
},
{
"name": "ondram/ci-detector",
"version": "3.4.0",
"source": {
"type": "git",
"url": "https://github.com/OndraM/ci-detector.git",
"reference": "0babf1cb71984f652498c6327a47d0081cd1e01b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/OndraM/ci-detector/zipball/0babf1cb71984f652498c6327a47d0081cd1e01b",
"reference": "0babf1cb71984f652498c6327a47d0081cd1e01b",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"ergebnis/composer-normalize": "^2.2",
"lmc/coding-standard": "^1.3 || ^2.0",
"php-coveralls/php-coveralls": "^2.2",
"php-parallel-lint/php-parallel-lint": "^1.1",
"phpstan/extension-installer": "^1.0.3",
"phpstan/phpstan": "^0.12.0",
"phpstan/phpstan-phpunit": "^0.12.1",
"phpunit/phpunit": "^7.1 || ^8.0 || ^9.0"
},
"type": "library",
"autoload": {
"psr-4": {
"OndraM\\CiDetector\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ondřej Machulda",
"email": "ondrej.machulda@gmail.com"
}
],
"description": "Detect continuous integration environment and provide unified access to properties of current build",
"keywords": [
"CircleCI",
"Codeship",
"adapter",
"appveyor",
"aws",
"aws codebuild",
"bamboo",
"bitbucket",
"buddy",
"codebuild",
"continuous integration",
"continuousphp",
"drone",
"github",
"gitlab",
"interface",
"jenkins",
"teamcity",
"travis"
],
"support": {
"issues": "https://github.com/OndraM/ci-detector/issues",
"source": "https://github.com/OndraM/ci-detector/tree/3.4.0"
},
"time": "2020-05-11T19:24:44+00:00"
},
{
"name": "openlss/lib-array2xml",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/nullivex/lib-array2xml.git",
"reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90",
"reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"type": "library",
"autoload": {
"psr-0": {
"LSS": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Bryan Tong",
"email": "bryan@nullivex.com",
"homepage": "https://www.nullivex.com"
},
{
"name": "Tony Butler",
"email": "spudz76@gmail.com",
"homepage": "https://www.nullivex.com"
}
],
"description": "Array2XML conversion library credit to lalit.org",
"homepage": "https://www.nullivex.com",
"keywords": [
"array",
"array conversion",
"xml",
"xml conversion"
],
"support": {
"issues": "https://github.com/nullivex/lib-array2xml/issues",
"source": "https://github.com/nullivex/lib-array2xml/tree/master"
},
"time": "2019-03-29T20:06:56+00:00"
},
{
"name": "phar-io/manifest",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/phar-io/manifest.git",
"reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
"reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-phar": "*",
"phar-io/version": "^2.0",
"php": "^5.6 || ^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
},
{
"name": "Sebastian Heuer",
"email": "sebastian@phpeople.de",
"role": "Developer"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "Developer"
}
],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
"support": {
"issues": "https://github.com/phar-io/manifest/issues",
"source": "https://github.com/phar-io/manifest/tree/master"
},
"time": "2018-07-08T19:23:20+00:00"
},
{
"name": "phar-io/version",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/phar-io/version.git",
"reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
"reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
"shasum": ""
},
"require": {
"php": "^5.6 || ^7.0"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
},
{
"name": "Sebastian Heuer",
"email": "sebastian@phpeople.de",
"role": "Developer"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "Developer"
}
],
"description": "Library for handling version information and constraints",
"support": {
"issues": "https://github.com/phar-io/version/issues",
"source": "https://github.com/phar-io/version/tree/master"
},
"time": "2018-07-08T19:19:57+00:00"
},
{
"name": "phpbench/container",
"version": "1.2",
"source": {
"type": "git",
"url": "https://github.com/phpbench/container.git",
"reference": "c0e3cbf1cd8f867c70b029cb6d1b0b39fe6d409d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpbench/container/zipball/c0e3cbf1cd8f867c70b029cb6d1b0b39fe6d409d",
"reference": "c0e3cbf1cd8f867c70b029cb6d1b0b39fe6d409d",
"shasum": ""
},
"require": {
"psr/container": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"PhpBench\\DependencyInjection\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Daniel Leech",
"email": "daniel@dantleech.com"
}
],
"description": "Simple, configurable, service container.",
"support": {
"issues": "https://github.com/phpbench/container/issues",
"source": "https://github.com/phpbench/container/tree/master"
},
"time": "2018-02-12T08:08:59+00:00"
},
{
"name": "phpbench/dom",
"version": "0.2.0",
"source": {
"type": "git",
"url": "https://github.com/phpbench/dom.git",
"reference": "b135378dd0004c05ba5446aeddaf0b83339c1c4c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpbench/dom/zipball/b135378dd0004c05ba5446aeddaf0b83339c1c4c",
"reference": "b135378dd0004c05ba5446aeddaf0b83339c1c4c",
"shasum": ""
},
"require": {
"ext-dom": "*",
"php": "^5.4|^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"PhpBench\\Dom\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Daniel Leech",
"email": "daniel@dantleech.com"
}
],
"description": "DOM wrapper to simplify working with the PHP DOM implementation",
"support": {
"issues": "https://github.com/phpbench/dom/issues",
"source": "https://github.com/phpbench/dom/tree/master"
},
"time": "2016-02-27T12:15:56+00:00"
},
{
"name": "phpbench/phpbench",
"version": "0.17.1",
"source": {
"type": "git",
"url": "https://github.com/phpbench/phpbench.git",
"reference": "3211debc3afb9da79d796cf7471d52cad97b17f1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpbench/phpbench/zipball/3211debc3afb9da79d796cf7471d52cad97b17f1",
"reference": "3211debc3afb9da79d796cf7471d52cad97b17f1",
"shasum": ""
},
"require": {
"beberlei/assert": "^2.4 || ^3.0",
"doctrine/annotations": "^1.2.7",
"ext-dom": "*",
"ext-json": "*",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"lstrojny/functional-php": "1.0 || ^1.2.3",
"php": "^7.2",
"phpbench/container": "~1.2",
"phpbench/dom": "~0.2.0",
"seld/jsonlint": "^1.1",
"symfony/console": "^4.2 || ^5.0",
"symfony/debug": "^4.2 || ^5.0",
"symfony/filesystem": "^4.2 || ^5.0",
"symfony/finder": "^4.2 || ^5.0",
"symfony/options-resolver": "^4.2 || ^5.0",
"symfony/process": "^4.2 || ^5.0",
"webmozart/path-util": "^2.3"
},
"require-dev": {
"doctrine/dbal": "^2.4",
"friendsofphp/php-cs-fixer": "^2.13.1",
"padraic/phar-updater": "^1.0",
"phpspec/prophecy": "^1.8",
"phpstan/phpstan": "^0.12.7",
"phpunit/phpunit": "^8.5"
},
"suggest": {
"ext-curl": "For (web) reports extension",
"ext-xdebug": "For Xdebug profiling extension."
},
"bin": [
"bin/phpbench"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"PhpBench\\": "lib/",
"PhpBench\\Extensions\\Dbal\\": "extensions/dbal/lib/",
"PhpBench\\Extensions\\XDebug\\": "extensions/xdebug/lib/",
"PhpBench\\Extensions\\Reports\\": "extensions/reports/lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Daniel Leech",
"email": "daniel@dantleech.com"
}
],
"description": "PHP Benchmarking Framework",
"support": {
"issues": "https://github.com/phpbench/phpbench/issues",
"source": "https://github.com/phpbench/phpbench/tree/master"
},
"time": "2020-06-13T11:59:17+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-2.x": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jaap van Otterdijk",
"email": "opensource@ijaap.nl"
}
],
"description": "Common reflection classes used by phpdocumentor to reflect the code structure",
"homepage": "http://www.phpdoc.org",
"keywords": [
"FQSEN",
"phpDocumentor",
"phpdoc",
"reflection",
"static analysis"
],
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
},
"time": "2020-06-27T09:03:43+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "5.1.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e",
"reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e",
"shasum": ""
},
"require": {
"ext-filter": "^7.1",
"php": "^7.2",
"phpdocumentor/reflection-common": "^2.0",
"phpdocumentor/type-resolver": "^1.0",
"webmozart/assert": "^1"
},
"require-dev": {
"doctrine/instantiator": "^1",
"mockery/mockery": "^1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "me@mikevanriel.com"
},
{
"name": "Jaap van Otterdijk",
"email": "account@ijaap.nl"
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.1.0"
},
"time": "2020-02-22T12:28:44+00:00"
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "e878a14a65245fbe78f8080eba03b47c3b705651"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e878a14a65245fbe78f8080eba03b47c3b705651",
"reference": "e878a14a65245fbe78f8080eba03b47c3b705651",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpdocumentor/reflection-common": "^2.0"
},
"require-dev": {
"ext-tokenizer": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-1.x": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "me@mikevanriel.com"
}
],
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.x"
},
"time": "2020-06-27T10:12:23+00:00"
},
{
"name": "phpspec/prophecy",
"version": "1.11.1",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "b20034be5efcdab4fb60ca3a29cba2949aead160"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/b20034be5efcdab4fb60ca3a29cba2949aead160",
"reference": "b20034be5efcdab4fb60ca3a29cba2949aead160",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.2",
"php": "^7.2",
"phpdocumentor/reflection-docblock": "^5.0",
"sebastian/comparator": "^3.0 || ^4.0",
"sebastian/recursion-context": "^3.0 || ^4.0"
},
"require-dev": {
"phpspec/phpspec": "^6.0",
"phpunit/phpunit": "^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.11.x-dev"
}
},
"autoload": {
"psr-4": {
"Prophecy\\": "src/Prophecy"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
},
{
"name": "Marcello Duarte",
"email": "marcello.duarte@gmail.com"
}
],
"description": "Highly opinionated mocking framework for PHP 5.3+",
"homepage": "https://github.com/phpspec/prophecy",
"keywords": [
"Double",
"Dummy",
"fake",
"mock",
"spy",
"stub"
],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
"source": "https://github.com/phpspec/prophecy/tree/master"
},
"time": "2020-07-08T12:44:21+00:00"
},
{
"name": "phpstan/phpdoc-parser",
"version": "0.4.4",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "d8d9d4645379e677466d407034436bb155b11c65"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/d8d9d4645379e677466d407034436bb155b11c65",
"reference": "d8d9d4645379e677466d407034436bb155b11c65",
"shasum": ""
},
"require": {
"php": "~7.1"
},
"require-dev": {
"consistence/coding-standard": "^3.5",
"ergebnis/composer-normalize": "^2.0.2",
"jakub-onderka/php-parallel-lint": "^0.9.2",
"phing/phing": "^2.16.0",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12.19",
"phpstan/phpstan-strict-rules": "^0.12",
"phpunit/phpunit": "^6.3",
"slevomat/coding-standard": "^4.7.2",
"symfony/process": "^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.4-dev"
}
},
"autoload": {
"psr-4": {
"PHPStan\\PhpDocParser\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/master"
},
"time": "2020-04-13T16:28:46+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "8.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc",
"reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xmlwriter": "*",
"php": "^7.3",
"phpunit/php-file-iterator": "^3.0",
"phpunit/php-text-template": "^2.0",
"phpunit/php-token-stream": "^4.0",
"sebastian/code-unit-reverse-lookup": "^2.0",
"sebastian/environment": "^5.0",
"sebastian/version": "^3.0",
"theseer/tokenizer": "^1.1.3"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"suggest": {
"ext-pcov": "*",
"ext-xdebug": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "8.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
"keywords": [
"coverage",
"testing",
"xunit"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/8.0.2"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-05-23T08:02:54+00:00"
},
{
"name": "phpunit/php-file-iterator",
"version": "3.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "25fefc5b19835ca653877fe081644a3f8c1d915e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/25fefc5b19835ca653877fe081644a3f8c1d915e",
"reference": "25fefc5b19835ca653877fe081644a3f8c1d915e",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": [
"filesystem",
"iterator"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.4"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-07-11T05:18:21+00:00"
},
{
"name": "phpunit/php-invoker",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-invoker.git",
"reference": "f6eedfed1085dd1f4c599629459a0277d25f9a66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f6eedfed1085dd1f4c599629459a0277d25f9a66",
"reference": "f6eedfed1085dd1f4c599629459a0277d25f9a66",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"ext-pcntl": "*",
"phpunit/phpunit": "^9.0"
},
"suggest": {
"ext-pcntl": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Invoke callables with a timeout",
"homepage": "https://github.com/sebastianbergmann/php-invoker/",
"keywords": [
"process"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-invoker/issues",
"source": "https://github.com/sebastianbergmann/php-invoker/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T11:53:53+00:00"
},
{
"name": "phpunit/php-text-template",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
"reference": "6ff9c8ea4d3212b88fcf74e25e516e2c51c99324"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/6ff9c8ea4d3212b88fcf74e25e516e2c51c99324",
"reference": "6ff9c8ea4d3212b88fcf74e25e516e2c51c99324",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Simple template engine.",
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
"keywords": [
"template"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
"source": "https://github.com/sebastianbergmann/php-text-template/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T11:55:37+00:00"
},
{
"name": "phpunit/php-timer",
"version": "5.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "cc49734779cbb302bf51a44297dab8c4bbf941e7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/cc49734779cbb302bf51a44297dab8c4bbf941e7",
"reference": "cc49734779cbb302bf51a44297dab8c4bbf941e7",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Utility class for timing",
"homepage": "https://github.com/sebastianbergmann/php-timer/",
"keywords": [
"timer"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
"source": "https://github.com/sebastianbergmann/php-timer/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T11:58:13+00:00"
},
{
"name": "phpunit/php-token-stream",
"version": "4.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "5672711b6b07b14d5ab694e700c62eeb82fcf374"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/5672711b6b07b14d5ab694e700c62eeb82fcf374",
"reference": "5672711b6b07b14d5ab694e700c62eeb82fcf374",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Wrapper around PHP's tokenizer extension.",
"homepage": "https://github.com/sebastianbergmann/php-token-stream/",
"keywords": [
"tokenizer"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
"source": "https://github.com/sebastianbergmann/php-token-stream/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-27T06:36:25+00:00"
},
{
"name": "phpunit/phpunit",
"version": "9.2.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6a9e4312e209e659f1fce3ce88dd197c2448f6",
"reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.3.1",
"ext-dom": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"myclabs/deep-copy": "^1.9.5",
"phar-io/manifest": "^1.0.3",
"phar-io/version": "^2.0.1",
"php": "^7.3",
"phpspec/prophecy": "^1.10.3",
"phpunit/php-code-coverage": "^8.0.2",
"phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-invoker": "^3.0.2",
"phpunit/php-text-template": "^2.0.2",
"phpunit/php-timer": "^5.0.1",
"sebastian/code-unit": "^1.0.5",
"sebastian/comparator": "^4.0.3",
"sebastian/diff": "^4.0.1",
"sebastian/environment": "^5.1.2",
"sebastian/exporter": "^4.0.2",
"sebastian/global-state": "^4.0",
"sebastian/object-enumerator": "^4.0.2",
"sebastian/resource-operations": "^3.0.2",
"sebastian/type": "^2.1.1",
"sebastian/version": "^3.0.1"
},
"require-dev": {
"ext-pdo": "*",
"phpspec/prophecy-phpunit": "^2.0"
},
"suggest": {
"ext-soap": "*",
"ext-xdebug": "*"
},
"bin": [
"phpunit"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "9.2-dev"
}
},
"autoload": {
"classmap": [
"src/"
],
"files": [
"src/Framework/Assert/Functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "The PHP Unit Testing framework.",
"homepage": "https://phpunit.de/",
"keywords": [
"phpunit",
"testing",
"xunit"
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.2.6"
},
"funding": [
{
"url": "https://phpunit.de/donate.html",
"type": "custom"
},
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-07-13T17:55:55+00:00"
},
{
"name": "psr/container",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP FIG PSR-11)",
"homepage": "https://github.com/php-fig/container",
"keywords": [
"PSR-11",
"container",
"container-interface",
"container-interop",
"psr"
],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/master"
},
"time": "2017-02-14T16:28:37+00:00"
},
{
"name": "psr/log",
"version": "1.1.3",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.3"
},
"time": "2020-03-23T09:12:05+00:00"
},
{
"name": "sanmai/pipeline",
"version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/sanmai/pipeline.git",
"reference": "12a7402b97d945587a6a8c291a0040369a83fcf6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sanmai/pipeline/zipball/12a7402b97d945587a6a8c291a0040369a83fcf6",
"reference": "12a7402b97d945587a6a8c291a0040369a83fcf6",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"codacy/coverage": "^1.4",
"friendsofphp/php-cs-fixer": "^2.13",
"infection/infection": ">=0.10.5",
"league/pipeline": "^1.0 || ^0.3",
"mockery/mockery": "^1.0",
"phan/phan": "^1.1 || ^2.0",
"php-coveralls/php-coveralls": "^2.0",
"phpstan/phpstan": ">=0.10",
"phpunit/phpunit": "^7.4 || ^8.1",
"vimeo/psalm": "^2.0 || ^3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"Pipeline\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Alexey Kopytko",
"email": "alexey@kopytko.com"
}
],
"description": "General-purpose collections pipeline",
"support": {
"issues": "https://github.com/sanmai/pipeline/issues",
"source": "https://github.com/sanmai/pipeline/tree/v3.1.2"
},
"time": "2020-01-26T21:22:49+00:00"
},
{
"name": "sebastian/code-unit",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/code-unit.git",
"reference": "c1e2df332c905079980b119c4db103117e5e5c90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/c1e2df332c905079980b119c4db103117e5e5c90",
"reference": "c1e2df332c905079980b119c4db103117e5e5c90",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Collection of value objects that represent the PHP code units",
"homepage": "https://github.com/sebastianbergmann/code-unit",
"support": {
"issues": "https://github.com/sebastianbergmann/code-unit/issues",
"source": "https://github.com/sebastianbergmann/code-unit/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T12:50:45+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
"reference": "ee51f9bb0c6d8a43337055db3120829fa14da819"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ee51f9bb0c6d8a43337055db3120829fa14da819",
"reference": "ee51f9bb0c6d8a43337055db3120829fa14da819",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Looks up which function or method a line of code belongs to",
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
"support": {
"issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
"source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T12:04:00+00:00"
},
{
"name": "sebastian/comparator",
"version": "4.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f",
"reference": "dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0",
"sebastian/diff": "^4.0",
"sebastian/exporter": "^4.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
}
],
"description": "Provides the functionality to compare PHP values for equality",
"homepage": "https://github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
"equality"
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T12:05:46+00:00"
},
{
"name": "sebastian/diff",
"version": "4.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113",
"reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0",
"symfony/process": "^4.2 || ^5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Kore Nordmann",
"email": "mail@kore-nordmann.de"
}
],
"description": "Diff implementation",
"homepage": "https://github.com/sebastianbergmann/diff",
"keywords": [
"diff",
"udiff",
"unidiff",
"unified diff"
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"source": "https://github.com/sebastianbergmann/diff/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-30T04:46:02+00:00"
},
{
"name": "sebastian/environment",
"version": "5.1.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2",
"reference": "0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"suggest": {
"ext-posix": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Provides functionality to handle HHVM/PHP environments",
"homepage": "http://www.github.com/sebastianbergmann/environment",
"keywords": [
"Xdebug",
"environment",
"hhvm"
],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"source": "https://github.com/sebastianbergmann/environment/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T12:07:24+00:00"
},
{
"name": "sebastian/exporter",
"version": "4.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "571d721db4aec847a0e59690b954af33ebf9f023"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/571d721db4aec847a0e59690b954af33ebf9f023",
"reference": "571d721db4aec847a0e59690b954af33ebf9f023",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0",
"sebastian/recursion-context": "^4.0"
},
"require-dev": {
"ext-mbstring": "*",
"phpunit/phpunit": "^9.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
}
],
"description": "Provides the functionality to export PHP variables for visualization",
"homepage": "http://www.github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.2"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T12:08:55+00:00"
},
{
"name": "sebastian/global-state",
"version": "4.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72",
"reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72",
"shasum": ""
},
"require": {
"php": "^7.3",
"sebastian/object-reflector": "^2.0",
"sebastian/recursion-context": "^4.0"
},
"require-dev": {
"ext-dom": "*",
"phpunit/phpunit": "^9.0"
},
"suggest": {
"ext-uopz": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Snapshotting of global state",
"homepage": "http://www.github.com/sebastianbergmann/global-state",
"keywords": [
"global state"
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/master"
},
"time": "2020-02-07T06:11:37+00:00"
},
{
"name": "sebastian/object-enumerator",
"version": "4.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
"reference": "074fed2d0a6d08e1677dd8ce9d32aecb384917b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/074fed2d0a6d08e1677dd8ce9d32aecb384917b8",
"reference": "074fed2d0a6d08e1677dd8ce9d32aecb384917b8",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0",
"sebastian/object-reflector": "^2.0",
"sebastian/recursion-context": "^4.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
"source": "https://github.com/sebastianbergmann/object-enumerator/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T12:11:32+00:00"
},
{
"name": "sebastian/object-reflector",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-reflector.git",
"reference": "127a46f6b057441b201253526f81d5406d6c7840"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/127a46f6b057441b201253526f81d5406d6c7840",
"reference": "127a46f6b057441b201253526f81d5406d6c7840",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Allows reflection of object attributes, including inherited and non-public ones",
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-reflector/issues",
"source": "https://github.com/sebastianbergmann/object-reflector/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T12:12:55+00:00"
},
{
"name": "sebastian/recursion-context",
"version": "4.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "062231bf61d2b9448c4fa5a7643b5e1829c11d63"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/062231bf61d2b9448c4fa5a7643b5e1829c11d63",
"reference": "062231bf61d2b9448c4fa5a7643b5e1829c11d63",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
}
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
"source": "https://github.com/sebastianbergmann/recursion-context/tree/master"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T12:14:17+00:00"
},
{
"name": "sebastian/resource-operations",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/resource-operations.git",
"reference": "0653718a5a629b065e91f774595267f8dc32e213"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0653718a5a629b065e91f774595267f8dc32e213",
"reference": "0653718a5a629b065e91f774595267f8dc32e213",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Provides a list of PHP built-in functions that operate on resources",
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
"support": {
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
"source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.2"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T12:16:22+00:00"
},
{
"name": "sebastian/type",
"version": "2.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
"reference": "86991e2b33446cd96e648c18bcdb1e95afb2c05a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/86991e2b33446cd96e648c18bcdb1e95afb2c05a",
"reference": "86991e2b33446cd96e648c18bcdb1e95afb2c05a",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Collection of value objects that represent the types of the PHP type system",
"homepage": "https://github.com/sebastianbergmann/type",
"support": {
"issues": "https://github.com/sebastianbergmann/type/issues",
"source": "https://github.com/sebastianbergmann/type/tree/2.2.1"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-07-05T08:31:53+00:00"
},
{
"name": "sebastian/version",
"version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
"reference": "626586115d0ed31cb71483be55beb759b5af5a3c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/626586115d0ed31cb71483be55beb759b5af5a3c",
"reference": "626586115d0ed31cb71483be55beb759b5af5a3c",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
"support": {
"issues": "https://github.com/sebastianbergmann/version/issues",
"source": "https://github.com/sebastianbergmann/version/tree/3.0.1"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-06-26T12:18:43+00:00"
},
{
"name": "seld/jsonlint",
"version": "1.8.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/jsonlint.git",
"reference": "ff2aa5420bfbc296cf6a0bc785fa5b35736de7c1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/ff2aa5420bfbc296cf6a0bc785fa5b35736de7c1",
"reference": "ff2aa5420bfbc296cf6a0bc785fa5b35736de7c1",
"shasum": ""
},
"require": {
"php": "^5.3 || ^7.0 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
},
"bin": [
"bin/jsonlint"
],
"type": "library",
"autoload": {
"psr-4": {
"Seld\\JsonLint\\": "src/Seld/JsonLint/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "JSON Linter",
"keywords": [
"json",
"linter",
"parser",
"validator"
],
"support": {
"issues": "https://github.com/Seldaek/jsonlint/issues",
"source": "https://github.com/Seldaek/jsonlint/tree/master"
},
"funding": [
{
"url": "https://github.com/Seldaek",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/seld/jsonlint",
"type": "tidelift"
}
],
"time": "2020-04-30T19:05:18+00:00"
},
{
"name": "slevomat/coding-standard",
"version": "6.3.10",
"source": {
"type": "git",
"url": "https://github.com/slevomat/coding-standard.git",
"reference": "58fa5ea2c048357ae55185eb5e93ca2826fffde0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slevomat/coding-standard/zipball/58fa5ea2c048357ae55185eb5e93ca2826fffde0",
"reference": "58fa5ea2c048357ae55185eb5e93ca2826fffde0",
"shasum": ""
},
"require": {
"php": "^7.1",
"phpstan/phpdoc-parser": "0.4.0 - 0.4.4",
"squizlabs/php_codesniffer": "^3.5.5"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "0.6.2",
"phing/phing": "2.16.3",
"php-parallel-lint/php-parallel-lint": "1.2.0",
"phpstan/phpstan": "0.12.19",
"phpstan/phpstan-deprecation-rules": "0.12.2",
"phpstan/phpstan-phpunit": "0.12.8",
"phpstan/phpstan-strict-rules": "0.12.2",
"phpunit/phpunit": "7.5.20|8.5.2|9.1.2"
},
"type": "phpcodesniffer-standard",
"extra": {
"branch-alias": {
"dev-master": "6.x-dev"
}
},
"autoload": {
"psr-4": {
"SlevomatCodingStandard\\": "SlevomatCodingStandard"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.",
"support": {
"issues": "https://github.com/slevomat/coding-standard/issues",
"source": "https://github.com/slevomat/coding-standard/tree/6.3.10"
},
"funding": [
{
"url": "https://github.com/kukulich",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard",
"type": "tidelift"
}
],
"time": "2020-06-22T11:33:09+00:00"
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.5.5",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
"reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
"shasum": ""
},
"require": {
"ext-simplexml": "*",
"ext-tokenizer": "*",
"ext-xmlwriter": "*",
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"bin": [
"bin/phpcs",
"bin/phpcbf"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Greg Sherwood",
"role": "lead"
}
],
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
"keywords": [
"phpcs",
"standards"
],
"support": {
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
},
"time": "2020-04-17T01:09:41+00:00"
},
{
"name": "symfony/config",
"version": "v5.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "b8623ef3d99fe62a34baf7a111b576216965f880"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/b8623ef3d99fe62a34baf7a111b576216965f880",
"reference": "b8623ef3d99fe62a34baf7a111b576216965f880",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1",
"symfony/filesystem": "^4.4|^5.0",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-php80": "^1.15"
},
"conflict": {
"symfony/finder": "<4.4"
},
"require-dev": {
"symfony/event-dispatcher": "^4.4|^5.0",
"symfony/finder": "^4.4|^5.0",
"symfony/messenger": "^4.4|^5.0",
"symfony/service-contracts": "^1.1|^2",
"symfony/yaml": "^4.4|^5.0"
},
"suggest": {
"symfony/yaml": "To use the yaml reference dumper"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Config\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/config/tree/v5.1.2"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-05-23T13:08:13+00:00"
},
{
"name": "symfony/console",
"version": "v5.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "34ac555a3627e324b660e318daa07572e1140123"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/34ac555a3627e324b660e318daa07572e1140123",
"reference": "34ac555a3627e324b660e318daa07572e1140123",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php73": "^1.8",
"symfony/polyfill-php80": "^1.15",
"symfony/service-contracts": "^1.1|^2",
"symfony/string": "^5.1"
},
"conflict": {
"symfony/dependency-injection": "<4.4",
"symfony/dotenv": "<5.1",
"symfony/event-dispatcher": "<4.4",
"symfony/lock": "<4.4",
"symfony/process": "<4.4"
},
"provide": {
"psr/log-implementation": "1.0"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "^4.4|^5.0",
"symfony/dependency-injection": "^4.4|^5.0",
"symfony/event-dispatcher": "^4.4|^5.0",
"symfony/lock": "^4.4|^5.0",
"symfony/process": "^4.4|^5.0",
"symfony/var-dumper": "^4.4|^5.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/console/tree/v5.1.2"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-06-15T12:59:21+00:00"
},
{
"name": "symfony/debug",
"version": "v4.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "28f92d08bb6d1fddf8158e02c194ad43870007e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/28f92d08bb6d1fddf8158e02c194ad43870007e6",
"reference": "28f92d08bb6d1fddf8158e02c194ad43870007e6",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"psr/log": "~1.0",
"symfony/polyfill-php80": "^1.15"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "^3.4|^4.0|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.4-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/debug/tree/4.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-05-24T08:33:35+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5e20b83385a77593259c9f8beb2c43cd03b2ac14",
"reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.1.3"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-06-06T08:49:21+00:00"
},
{
"name": "symfony/filesystem",
"version": "v4.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "b27f491309db5757816db672b256ea2e03677d30"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/b27f491309db5757816db672b256ea2e03677d30",
"reference": "b27f491309db5757816db672b256ea2e03677d30",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"symfony/polyfill-ctype": "~1.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.4-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v4.4.10"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-05-30T18:50:54+00:00"
},
{
"name": "symfony/finder",
"version": "v5.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "4298870062bfc667cb78d2b379be4bf5dec5f187"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/4298870062bfc667cb78d2b379be4bf5dec5f187",
"reference": "4298870062bfc667cb78d2b379be4bf5dec5f187",
"shasum": ""
},
"require": {
"php": ">=7.2.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Finder\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/5.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-05-20T17:43:50+00:00"
},
{
"name": "symfony/options-resolver",
"version": "v5.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "663f5dd5e14057d1954fe721f9709d35837f2447"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/663f5dd5e14057d1954fe721f9709d35837f2447",
"reference": "663f5dd5e14057d1954fe721f9709d35837f2447",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1",
"symfony/polyfill-php80": "^1.15"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\OptionsResolver\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony OptionsResolver Component",
"homepage": "https://symfony.com",
"keywords": [
"config",
"configuration",
"options"
],
"support": {
"source": "https://github.com/symfony/options-resolver/tree/5.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-05-23T13:08:13+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.17.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
"reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.17-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.17.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-06-06T08:46:27+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.17.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "6e4dbcf5e81eba86e36731f94fe56b1726835846"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/6e4dbcf5e81eba86e36731f94fe56b1726835846",
"reference": "6e4dbcf5e81eba86e36731f94fe56b1726835846",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.17-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Intl\\Grapheme\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's grapheme_* functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"grapheme",
"intl",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.17.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-06-06T08:46:27+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.17.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "40309d1700e8f72447bb9e7b54af756eeea35620"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/40309d1700e8f72447bb9e7b54af756eeea35620",
"reference": "40309d1700e8f72447bb9e7b54af756eeea35620",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.17-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
},
"files": [
"bootstrap.php"
],
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's Normalizer class and related functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"intl",
"normalizer",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/master"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-06-14T14:40:37+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.17.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "7110338d81ce1cbc3e273136e4574663627037a7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7110338d81ce1cbc3e273136e4574663627037a7",
"reference": "7110338d81ce1cbc3e273136e4574663627037a7",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.17-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/master"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-06-06T08:46:27+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.17.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fa0837fe02d617d31fbb25f990655861bb27bd1a",
"reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.17-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php73\\": ""
},
"files": [
"bootstrap.php"
],
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.17.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-06-06T08:46:27+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.17.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2",
"reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2",
"shasum": ""
},
"require": {
"php": ">=7.0.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.17-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"files": [
"bootstrap.php"
],
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.17.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-06-06T08:46:27+00:00"
},
{
"name": "symfony/process",
"version": "v5.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "7f6378c1fa2147eeb1b4c385856ce9de0d46ebd1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/7f6378c1fa2147eeb1b4c385856ce9de0d46ebd1",
"reference": "7f6378c1fa2147eeb1b4c385856ce9de0d46ebd1",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-php80": "^1.15"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v5.1.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-05-30T20:35:19+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "58c7475e5457c5492c26cc740cc0ad7464be9442"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/58c7475e5457c5492c26cc740cc0ad7464be9442",
"reference": "58c7475e5457c5492c26cc740cc0ad7464be9442",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/container": "^1.0"
},
"suggest": {
"symfony/service-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to writing services",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v2.1.3"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-07-06T13:23:11+00:00"
},
{
"name": "symfony/string",
"version": "v5.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "ac70459db781108db7c6d8981dd31ce0e29e3298"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/ac70459db781108db7c6d8981dd31ce0e29e3298",
"reference": "ac70459db781108db7c6d8981dd31ce0e29e3298",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-grapheme": "~1.0",
"symfony/polyfill-intl-normalizer": "~1.0",
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "~1.15"
},
"require-dev": {
"symfony/error-handler": "^4.4|^5.0",
"symfony/http-client": "^4.4|^5.0",
"symfony/translation-contracts": "^1.1|^2",
"symfony/var-exporter": "^4.4|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\String\\": ""
},
"files": [
"Resources/functions.php"
],
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony String component",
"homepage": "https://symfony.com",
"keywords": [
"grapheme",
"i18n",
"string",
"unicode",
"utf-8",
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/5.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-06-11T12:16:36+00:00"
},
{
"name": "thecodingmachine/safe",
"version": "v1.1.3",
"source": {
"type": "git",
"url": "https://github.com/thecodingmachine/safe.git",
"reference": "9f277171e296a3c8629c04ac93ec95ff0f208ccb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thecodingmachine/safe/zipball/9f277171e296a3c8629c04ac93ec95ff0f208ccb",
"reference": "9f277171e296a3c8629c04ac93ec95ff0f208ccb",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"require-dev": {
"phpstan/phpstan": "^0.12",
"squizlabs/php_codesniffer": "^3.2",
"thecodingmachine/phpstan-strict-rules": "^0.12"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.1-dev"
}
},
"autoload": {
"psr-4": {
"Safe\\": [
"lib/",
"generated/"
]
},
"files": [
"generated/apache.php",
"generated/apc.php",
"generated/apcu.php",
"generated/array.php",
"generated/bzip2.php",
"generated/classobj.php",
"generated/com.php",
"generated/cubrid.php",
"generated/curl.php",
"generated/datetime.php",
"generated/dir.php",
"generated/eio.php",
"generated/errorfunc.php",
"generated/exec.php",
"generated/fileinfo.php",
"generated/filesystem.php",
"generated/filter.php",
"generated/fpm.php",
"generated/ftp.php",
"generated/funchand.php",
"generated/gmp.php",
"generated/gnupg.php",
"generated/hash.php",
"generated/ibase.php",
"generated/ibmDb2.php",
"generated/iconv.php",
"generated/image.php",
"generated/imap.php",
"generated/info.php",
"generated/ingres-ii.php",
"generated/inotify.php",
"generated/json.php",
"generated/ldap.php",
"generated/libevent.php",
"generated/libxml.php",
"generated/lzf.php",
"generated/mailparse.php",
"generated/mbstring.php",
"generated/misc.php",
"generated/msql.php",
"generated/mssql.php",
"generated/mysql.php",
"generated/mysqli.php",
"generated/mysqlndMs.php",
"generated/mysqlndQc.php",
"generated/network.php",
"generated/oci8.php",
"generated/opcache.php",
"generated/openssl.php",
"generated/outcontrol.php",
"generated/password.php",
"generated/pcntl.php",
"generated/pcre.php",
"generated/pdf.php",
"generated/pgsql.php",
"generated/posix.php",
"generated/ps.php",
"generated/pspell.php",
"generated/readline.php",
"generated/rpminfo.php",
"generated/rrd.php",
"generated/sem.php",
"generated/session.php",
"generated/shmop.php",
"generated/simplexml.php",
"generated/sockets.php",
"generated/sodium.php",
"generated/solr.php",
"generated/spl.php",
"generated/sqlsrv.php",
"generated/ssdeep.php",
"generated/ssh2.php",
"generated/stats.php",
"generated/stream.php",
"generated/strings.php",
"generated/swoole.php",
"generated/uodbc.php",
"generated/uopz.php",
"generated/url.php",
"generated/var.php",
"generated/xdiff.php",
"generated/xml.php",
"generated/xmlrpc.php",
"generated/yaml.php",
"generated/yaz.php",
"generated/zip.php",
"generated/zlib.php",
"lib/special_cases.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHP core functions that throw exceptions instead of returning FALSE on error",
"support": {
"issues": "https://github.com/thecodingmachine/safe/issues",
"source": "https://github.com/thecodingmachine/safe/tree/master"
},
"time": "2020-07-10T09:34:29+00:00"
},
{
"name": "theseer/tokenizer",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
"reference": "75a63c33a8577608444246075ea0af0d052e452a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a",
"reference": "75a63c33a8577608444246075ea0af0d052e452a",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-tokenizer": "*",
"ext-xmlwriter": "*",
"php": "^7.2 || ^8.0"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
}
],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/master"
},
"funding": [
{
"url": "https://github.com/theseer",
"type": "github"
}
],
"time": "2020-07-12T23:59:07+00:00"
},
{
"name": "twig/twig",
"version": "v2.13.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "46a612ba1bbf6ee1c58acabacd868212ff8a2911"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/46a612ba1bbf6ee1c58acabacd868212ff8a2911",
"reference": "46a612ba1bbf6ee1c58acabacd868212ff8a2911",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"psr/container": "^1.0",
"symfony/phpunit-bridge": "^4.4.9|^5.0.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.13-dev"
}
},
"autoload": {
"psr-0": {
"Twig_": "lib/"
},
"psr-4": {
"Twig\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Twig Team",
"role": "Contributors"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com",
"role": "Project Founder"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "https://twig.symfony.com",
"keywords": [
"templating"
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/2.x"
},
"funding": [
{
"url": "https://certification.symfony.com/",
"type": "custom"
},
{
"url": "https://live.symfony.com/",
"type": "custom"
},
{
"url": "https://symfony.com/cloud/",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"time": "2020-07-05T13:08:05+00:00"
},
{
"name": "vimeo/psalm",
"version": "3.12.2",
"source": {
"type": "git",
"url": "https://github.com/vimeo/psalm.git",
"reference": "7c7ebd068f8acaba211d4a2c707c4ba90874fa26"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vimeo/psalm/zipball/7c7ebd068f8acaba211d4a2c707c4ba90874fa26",
"reference": "7c7ebd068f8acaba211d4a2c707c4ba90874fa26",
"shasum": ""
},
"require": {
"amphp/amp": "^2.1",
"amphp/byte-stream": "^1.5",
"composer/semver": "^1.4 || ^2.0 || ^3.0",
"composer/xdebug-handler": "^1.1",
"ext-dom": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-simplexml": "*",
"ext-tokenizer": "*",
"felixfbecker/advanced-json-rpc": "^3.0.3",
"felixfbecker/language-server-protocol": "^1.4",
"netresearch/jsonmapper": "^1.0 || ^2.0",
"nikic/php-parser": "^4.3",
"ocramius/package-versions": "^1.2",
"openlss/lib-array2xml": "^1.0",
"php": "^7.1.3|^8",
"sebastian/diff": "^3.0 || ^4.0",
"symfony/console": "^3.4.17 || ^4.1.6 || ^5.0",
"webmozart/glob": "^4.1",
"webmozart/path-util": "^2.3"
},
"provide": {
"psalm/psalm": "self.version"
},
"require-dev": {
"amphp/amp": "^2.4.2",
"bamarni/composer-bin-plugin": "^1.2",
"brianium/paratest": "^4.0.0",
"ext-curl": "*",
"php-coveralls/php-coveralls": "^2.2",
"phpmyadmin/sql-parser": "5.1.0",
"phpspec/prophecy": ">=1.9.0",
"phpunit/phpunit": "^7.5.16 || ^8.5 || ^9.0",
"psalm/plugin-phpunit": "^0.10",
"slevomat/coding-standard": "^5.0",
"squizlabs/php_codesniffer": "^3.5",
"symfony/process": "^4.3"
},
"suggest": {
"ext-igbinary": "^2.0.5"
},
"bin": [
"psalm",
"psalm-language-server",
"psalm-plugin",
"psalm-refactor",
"psalter"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev",
"dev-2.x": "2.x-dev",
"dev-1.x": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psalm\\": "src/Psalm/"
},
"files": [
"src/functions.php",
"src/spl_object_id.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Matthew Brown"
}
],
"description": "A static analysis tool for finding errors in PHP applications",
"keywords": [
"code",
"inspection",
"php"
],
"support": {
"issues": "https://github.com/vimeo/psalm/issues",
"source": "https://github.com/vimeo/psalm/tree/master"
},
"time": "2020-07-03T16:59:07+00:00"
},
{
"name": "webmozart/assert",
"version": "1.9.1",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389",
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0 || ^8.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"phpstan/phpstan": "<0.12.20",
"vimeo/psalm": "<3.9.1"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
},
"type": "library",
"autoload": {
"psr-4": {
"Webmozart\\Assert\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
}
],
"description": "Assertions to validate method input/output with nice error messages.",
"keywords": [
"assert",
"check",
"validate"
],
"support": {
"issues": "https://github.com/webmozart/assert/issues",
"source": "https://github.com/webmozart/assert/tree/master"
},
"time": "2020-07-08T17:02:28+00:00"
},
{
"name": "webmozart/glob",
"version": "4.1.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/glob.git",
"reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/glob/zipball/3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe",
"reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe",
"shasum": ""
},
"require": {
"php": "^5.3.3|^7.0",
"webmozart/path-util": "^2.2"
},
"require-dev": {
"phpunit/phpunit": "^4.6",
"sebastian/version": "^1.0.1",
"symfony/filesystem": "^2.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
},
"autoload": {
"psr-4": {
"Webmozart\\Glob\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
}
],
"description": "A PHP implementation of Ant's glob.",
"support": {
"issues": "https://github.com/webmozart/glob/issues",
"source": "https://github.com/webmozart/glob/tree/master"
},
"time": "2015-12-29T11:14:33+00:00"
},
{
"name": "webmozart/path-util",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/path-util.git",
"reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725",
"reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"webmozart/assert": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.6",
"sebastian/version": "^1.0.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
}
},
"autoload": {
"psr-4": {
"Webmozart\\PathUtil\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
}
],
"description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.",
"support": {
"issues": "https://github.com/webmozart/path-util/issues",
"source": "https://github.com/webmozart/path-util/tree/2.3.0"
},
"time": "2015-12-17T08:42:14+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": "~7.4.1",
"composer-runtime-api": "^2.0.0"
},
"platform-dev": {
"ext-phar": "*"
},
"plugin-api-version": "2.0.0"
}
docs/access-interceptor-scope-localizer.md 0000644 00000006607 13721511157 0014720 0 ustar 00 ---
title: Access Interceptor Scope Localizer Proxy
---
# Access Interceptor Scope Localizer Proxy
An access interceptor scope localizer is a smart reference proxy that allows you to dynamically define logic to be executed
before or after any of the proxied object methods' logic.
It works exactly like the [access interceptor value holder](access-interceptor-value-holder.md), with some minor differences
in behaviour.
The working concept of an access interceptor scope localizer is to localize scope of a proxied object:
```php
class Example
{
protected $foo;
protected $bar;
protected $baz;
public function doFoo()
{
// ...
}
}
class ExampleProxy extends Example
{
public function __construct(Example $example)
{
$this->foo = & $example->foo;
$this->bar = & $example->bar;
$this->baz = & $example->baz;
}
public function doFoo()
{
return parent::doFoo();
}
}
```
This allows creating a mirror copy of the real instance, where any change in the proxy or the real instance is reflected in
both objects.
The main advantage of this approach is that the proxy is now safe against fluent interfaces, which would break an
[access interceptor value holder](access-interceptor-value-holder.md) instead.
## Differences with [access interceptor value holder](access-interceptor-value-holder.md):
* It does **NOT** implement the `ProxyManager\Proxy\ValueHolderInterface`, since the proxy itself does not keep a reference
to the original object being proxied
* In all interceptor methods (see [access interceptor value holder](access-interceptor-value-holder.md)), the `$instance`
passed in is the proxy itself. There is no way to gather a reference to the original object right now, and that is mainly
to protect from misuse.
## Known limitations
* It is **NOT** possible to intercept access to public properties
* It is **NOT** possible to proxy interfaces, since this proxy relies on `parent::method()` calls. Interfaces don't provide
a parent method implementation.
* calling `unset` on a property of an access interceptor scope localizer (or the real instance) will cause the two objects
to be un-synchronized, with possible unexpected behaviour.
* serializing or un-serializing an access interceptor scope localizer (or the real instance) will not cause the real
instance (or the proxy) to be serialized or un-serialized
* methods using `func_get_args()`, `func_get_arg()` and `func_num_arg()` will not function properly for parameters that are
not part of the proxied object interface: use
[variadic arguments](http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list) instead.
## Example
Here's an example of how you can create and use an access interceptor scope localizer:
```php
createProxy(
new Foo(),
['doFoo' => function () { echo "PreFoo!\n"; }],
['doFoo' => function () { echo "PostFoo!\n"; }]
);
$proxy->doFoo();
```
This sends something like following to your output:
```
PreFoo!
Foo!
PostFoo!
```
This is similar logic to what you can find in [access interceptor value holder](access-interceptor-value-holder.md).
docs/access-interceptor-value-holder.md 0000644 00000007615 13721511157 0014214 0 ustar 00 ---
title: Access Interceptor Value Holder Proxy
---
# Access Interceptor Value Holder Proxy
An *access interceptor value holder* is a smart reference proxy that allows you to dynamically define the logic that will be executed before or after any of the wrapped object's methods logic.
It wraps around a real instance of the object to be proxied and can be useful for things like:
* caching execution of slow and heavy methods
* log method calls
* debugging
* event triggering
* handling of orthogonal logic, and [AOP](http://en.wikipedia.org/wiki/Aspect-oriented_programming) in general
## Example
Here's an example of how you can create and use an access interceptor value holder:
```php
createProxy(
new Foo(),
['doFoo' => function () { echo "PreFoo!\n"; }],
['doFoo' => function () { echo "PostFoo!\n"; }]
);
$proxy->doFoo();
```
This sends something like following to your output:
```
PreFoo!
Foo!
PostFoo!
```
## Implementing pre- and post- access interceptors
A proxy produced by the
[`ProxyManager\Factory\AccessInterceptorValueHolderFactory`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Factory/AccessInterceptorValueHolderFactory.php)
implements the [`ProxyManager\Proxy\AccessInterceptorValueHolderInterface`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Proxy/AccessInterceptorValueHolderInterface.php).
Therefore, you can set an access interceptor callback by calling:
```php
$proxy->setMethodPrefixInterceptor('methodName', function () { echo 'pre'; });
$proxy->setMethodSuffixInterceptor('methodName', function () { echo 'post'; });
```
You can also listen to public properties access by attaching interceptors to `__get`, `__set`, `__isset` and `__unset`.
A prefix interceptor (executed before method logic) should have the following signature:
```php
/**
* @var object $proxy the proxy that intercepted the method call
* @var object $instance the wrapped instance within the proxy
* @var string $method name of the called method
* @var array $params sorted array of parameters passed to the intercepted
* method, indexed by parameter name
* @var bool $returnEarly flag to tell the interceptor proxy to return early, returning
* the interceptor's return value instead of executing the method logic
*
* @return mixed
*/
$prefixInterceptor = function ($proxy, $instance, $method, $params, & $returnEarly) {};
```
A suffix interceptor (executed after method logic) should have the following signature:
```php
/**
* @var object $proxy the proxy that intercepted the method call
* @var object $instance the wrapped instance within the proxy
* @var string $method name of the called method
* @var array $params sorted array of parameters passed to the intercepted
* method, indexed by parameter name
* @var mixed $returnValue the return value of the intercepted method
* @var bool $returnEarly flag to tell the proxy to return early, returning the interceptor's
* return value instead of the value produced by the method
*
* @return mixed
*/
$suffixInterceptor = function ($proxy, $instance, $method, $params, $returnValue, & $returnEarly) {};
```
## Known limitations
* methods using `func_get_args()`, `func_get_arg()` and `func_num_arg()` will not function properly for parameters that are
not part of the proxied object interface: use
[variadic arguments](http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list) instead.
## Tuning performance for production
See [Tuning ProxyManager for Production](tuning-for-production.md).
docs/copyright.md 0000644 00000002111 13721511157 0010024 0 ustar 00 ---
title: License
---
# License
Copyright (c) 2013 Marco Pivetta
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
docs/credits.md 0000644 00000002011 13721511157 0007450 0 ustar 00 ---
title: Credits
---
# Credits
The idea was originated by a [talk about Proxies in PHP OOP](https://ocramius.github.io/presentations/proxy-pattern-in-php/) that I gave at
the [@phpugffm](https://twitter.com/phpugffm) in January 2013.
---
### Contributors
- [Marco Pivetta](https://github.com/Ocramius)
- [Jefersson Nathan](https://github.com/malukenho)
- [Blanchon Vincent](https://github.com/blanchonvincent)
- [Markus Staab](https://github.com/staabm)
- [Gordon Stratton](https://github.com/gws)
- [Prolic](https://github.com/prolic)
- [Guillaume Royer](https://github.com/guilro)
- [Robert Reiz](https://github.com/reiz)
- [Lee Davis](https://github.com/leedavis81)
- [flip111](https://github.com/flip111)
- [Krzysztof Menzyk](https://github.com/krymen)
- [Aleksey Khudyakov](https://github.com/Xerkus)
- [Alexander](https://github.com/asm89)
- [Raul Fraile](https://github.com/raulfraile)
### Documentation
[Gary Hockin](https://twitter.com/GeeH) is amazing and spent literally 20 minutes tidying up the documentation.
docs/download.md 0000644 00000000325 13721511157 0007630 0 ustar 00 ---
title: Download / Installation
---
## Download / Installation
The suggested installation method is via [composer](https://getcomposer.org/).
```sh
php composer.phar require ocramius/proxy-manager:1.0.*
```
docs/generator-strategies.md 0000644 00000002737 13721511157 0012170 0 ustar 00 ---
title: Generator strategies
---
# Generator strategies
ProxyManager allows you to generate classes based on generator strategies and a given `Laminas\Code\Generator\ClassGenerator` as of the [interface of a generator strategy](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/GeneratorStrategy/GeneratorStrategyInterface.php).
Currently, 3 generator strategies are shipped with ProxyManager:
* [`ProxyManager\GeneratorStrategy\BaseGeneratorStrategy`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/GeneratorStrategy/BaseGeneratorStrategy.php)
which retrieves the string representation of the class from `ClassGenerator`
* [`ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/GeneratorStrategy/EvaluatingGeneratorStrategy.php)
which calls `eval()` upon the generated class code before returning it. This is useful in cases where you want to generate
multiple classes at runtime
* [`ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/GeneratorStrategy/FileWriterGeneratorStrategy.php)
which accepts a
[`ProxyManager\FileLocator\FileLocatorInterface`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/FileLocator/FileLocatorInterface.php)
instance as constructor parameter, and based on it, writes the generated class to a file before returning its code.
docs/lazy-loading-ghost-object.md 0000644 00000031036 13721511157 0013004 0 ustar 00 ---
title: Lazy Loading Ghost Object Proxies
---
# Lazy Loading Ghost Object Proxies
A Lazy Loading Ghost is a type of proxy object.
More specifically, it is a fake object that looks exactly like an object that you want to interact with but is just an empty
instance that gets all properties populated as soon as they are needed.
Those properties do not actually exist until the ghost object is initialized.
## Lazy loading with the Ghost Object
In pseudo-code, in userland, [lazy loading](http://www.martinfowler.com/eaaCatalog/lazyLoad.html) in a ghost object looks
like following:
```php
class MyObjectProxy
{
private $initialized = false;
private $name;
private $surname;
public function doFoo()
{
$this->init();
// Perform doFoo routine using loaded variables
}
private function init()
{
if (! $this->initialized) {
$data = some_logic_that_loads_data();
$this->name = $data['name'];
$this->surname = $data['surname'];
$this->initialized = true;
}
}
}
```
Ghost objects work similarly to virtual proxies, but since they do not wrap around a "real" instance of the proxied subject,
they are better suited for representing dataset rows.
## When do I use a ghost object?
You usually need a ghost object in cases where the following applies:
* you are building a small data-mapper and want to lazily load data across associations in your object graph
* you want to initialize objects representing rows in a large dataset
* you want to compare instances of lazily initialized objects without the risk of comparing a proxy with a real subject
* you are aware of the internal state of the object and are confident in working with its internals via reflection or direct
property access
## Usage examples
[ProxyManager](https://github.com/Ocramius/ProxyManager) provides a factory that creates lazy loading ghost objects.
To use it, follow these steps:
First, define your object's logic without taking care of lazy loading:
```php
namespace MyApp;
class Customer
{
private $name;
private $surname;
// just write your business logic or generally logic
// don't worry about how complex this object will be!
// don't code lazy-loading oriented optimizations in here!
public function getName() { return $this->name; }
public function setName($name) { $this->name = (string) $name; }
public function getSurname() { return $this->surname; }
public function setSurname($surname) { $this->surname = (string) $surname; }
}
```
Then, use the proxy manager to create a ghost object of it. You will be responsible for setting its state during lazy loading:
```php
namespace MyApp;
use ProxyManager\Factory\LazyLoadingGhostFactory;
use ProxyManager\Proxy\GhostObjectInterface;
require_once __DIR__ . '/vendor/autoload.php';
$factory = new LazyLoadingGhostFactory();
$initializer = function (
GhostObjectInterface $ghostObject,
string $method,
array $parameters,
& $initializer,
array $properties
) {
$initializer = null; // disable initialization
// load data and modify the object here
$properties["\0MyApp\\Customer\0name"] = 'Agent';
$properties["\0MyApp\\Customer\0surname"] = 'Smith';
// you may also call methods on the object, but remember that
// the constructor was not called yet:
$ghostObject->setSurname('Smith');
return true; // confirm that initialization occurred correctly
};
$ghostObject = $factory->createProxy(\MyApp\Customer::class, $initializer);
```
You can now use your object as before:
```php
// this will work as before
echo $ghostObject->getName() . ' ' . $ghostObject->getSurname(); // Agent Smith
```
## Lazy Initialization
We use a closure to handle lazy initialization of the proxy instance at runtime.
The initializer closure signature for ghost objects is:
```php
/**
* @var object $ghostObject The instance of the ghost object proxy that is being initialized.
* @var string $method The name of the method that triggered lazy initialization.
* @var array $parameters An ordered list of parameters passed to the method that
* triggered initialization, indexed by parameter name.
* @var Closure $initializer A reference to the property that is the initializer for the
* proxy. Set it to null to disable further initialization.
* @var array $properties By-ref array with the properties defined in the object, with their
* default values pre-assigned. Keys are in the same format that
* an (array) cast of an object would provide:
* - `"\0Ns\\ClassName\0propertyName"` for `private $propertyName`
* defined on `Ns\ClassName`
* - `"\0Ns\\ClassName\0propertyName"` for `protected $propertyName`
* defined in any level of the hierarchy
* - `"propertyName"` for `public $propertyName`
* defined in any level of the hierarchy
*
* @return bool true on success
*/
$initializer = function (
\ProxyManager\Proxy\GhostObjectInterface $ghostObject,
string $method,
array $parameters,
& $initializer,
array $properties
) {};
```
The initializer closure should usually look like:
```php
$initializer = function (
\ProxyManager\Proxy\GhostObjectInterface $ghostObject,
string $method,
array $parameters,
& $initializer,
array $properties
) {
$initializer = null; // disable initializer for this proxy instance
// initialize properties (please read further on)
$properties["\0ClassName\0foo"] = 'foo';
$properties["\0ClassName\0bar"] = 'bar';
return true; // report success
};
```
### Lazy initialization `$properties` explained
The assignments to properties in this closure use unusual `"\0"` sequences. This is to be consistent with how PHP represents
private and protected properties when casting an object to an array. `ProxyManager` copies a reference to the properties into
the `$properties` array passed to the initializer, which allows you to set the state of the object without accessing any of
its public API. (This is a significant detail for mapper implementations!)
Specifically:
* `"\0Ns\\ClassName\0propertyName"` means `private $propertyName` defined in `Ns\ClassName`;
* `"\0*\0propertyName"` means `protected $propertyName` defined in any level of the class
hierarchy;
* `"propertyName"` means `public $propertyName` defined in any level of the class hierarchy.
Therefore, given this class:
```php
namespace MyNamespace;
class MyClass
{
private $property1;
protected $property2;
public $property3;
}
```
Its appropriate initialization code would be:
```php
namespace MyApp;
use ProxyManager\Factory\LazyLoadingGhostFactory;
use ProxyManager\Proxy\GhostObjectInterface;
require_once __DIR__ . '/vendor/autoload.php';
$factory = new LazyLoadingGhostFactory();
$initializer = function (
GhostObjectInterface $ghostObject,
string $method,
array $parameters,
& $initializer,
array $properties
) {
$initializer = null;
$properties["\0MyNamespace\\MyClass\0property1"] = 'foo'; //private property of MyNamespace\MyClass
$properties["\0*\0property2"] = 'bar'; //protected property in MyClass's hierarchy
$properties["property3"] = 'baz'; //public property in MyClass's hierarchy
return true;
};
$instance = $factory->createProxy(\MyNamespace\MyClass::class, $initializer);
```
This code would initialize `$property1`, `$property2` and `$property3` respectively to `"foo"`, `"bar"` and `"baz"`.
You may read the default values for those properties by reading the respective array keys.
Although it is possible to initialize the object by interacting with its public API, it is not safe to do so, because the
object only contains default property values as its constructor was not called.
## Proxy implementation
The
[`ProxyManager\Factory\LazyLoadingGhostFactory`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Factory/LazyLoadingGhostFactory.php)
produces proxies that implement the
[`ProxyManager\Proxy\GhostObjectInterface`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Proxy/GhostObjectInterface.php).
At any point in time, you can set a new initializer for the proxy:
```php
$ghostObject->setProxyInitializer($initializer);
```
In your initializer, you **MUST** turn off any further initialization:
```php
$ghostObject->setProxyInitializer(null);
```
or
```php
$initializer = null; // if you use the initializer passed by reference to the closure
```
Remember to call `$ghostObject->setProxyInitializer(null);`, or to set `$initializer = null` inside your initializer closure
to disable initialization of your proxy, otherwise initialization will trigger more than once.
## Triggering Initialization
A lazy loading ghost object is initialized whenever you access any of its properties.
Any of the following interactions would trigger lazy initialization:
```php
// calling a method (only if the method accesses internal state)
$ghostObject->someMethod();
// reading a property
echo $ghostObject->someProperty;
// writing a property
$ghostObject->someProperty = 'foo';
// checking for existence of a property
isset($ghostObject->someProperty);
// removing a property
unset($ghostObject->someProperty);
// accessing a property via reflection
$reflection = new \ReflectionProperty($ghostObject, 'someProperty');
$reflection->setAccessible(true);
$reflection->getValue($ghostObject);
// cloning the entire proxy
clone $ghostObject;
// serializing the proxy
$unserialized = unserialize(serialize($ghostObject));
```
A method like following would never trigger lazy loading, in the context of a ghost object:
```php
class Hello
{
public function sayHello() : string
{
return 'Look ma! No property accessed!';
}
}
```
## Skipping properties (properties that should not be initialized)
In some contexts, you may want some properties to be ignored entirely by the lazy-loading system.
An example for that (in data mappers) is entities with identifiers: an identifier is usually:
* lightweight
* known at all times
This means that it can be set in our object at all times, and we never need to lazy-load it. Here is a typical example:
```php
namespace MyApp;
class User
{
private $id;
private $username;
private $passwordHash;
private $email;
private $address;
// ...
public function getId() : int
{
return $this->id;
}
}
```
If we want to skip the property `$id` from lazy-loading, we might want to tell that to the `LazyLoadingGhostFactory`. Here is
a longer example, with a more real-world scenario:
```php
namespace MyApp;
use ProxyManager\Factory\LazyLoadingGhostFactory;
use ProxyManager\Proxy\GhostObjectInterface;
require_once __DIR__ . '/vendor/autoload.php';
$factory = new LazyLoadingGhostFactory();
$initializer = function (
GhostObjectInterface $ghostObject,
string $method,
array $parameters,
& $initializer,
array $properties
) {
$initializer = null;
// note that `getId` won't initialize our proxy here
$properties["\0MyApp\\User\0username"] = $db->fetchField('users', 'username', $ghostObject->getId());
$properties["\0MyApp\\User\0passwordHash"] = $db->fetchField('users', 'passwordHash', $ghostObject->getId());
$properties["\0MyApp\\User\0email"] = $db->fetchField('users', 'email', $ghostObject->getId());
$properties["\0MyApp\\User\0address"] = $db->fetchField('users', 'address', $ghostObject->getId());
return true;
};
$proxyOptions = [
'skippedProperties' => [
"\0MyApp\\User\0id",
],
];
$instance = $factory->createProxy(User::class, $initializer, $proxyOptions);
$idReflection = new \ReflectionProperty(User::class, 'id');
$idReflection->setAccessible(true);
// write the identifier into our ghost object (assuming `setId` doesn't exist)
$idReflection->setValue($instance, 1234);
```
In this example, we pass a `skippedProperties` array to our proxy factory. Note the use of the `"\0"` parameter syntax as
described above.
## Proxying interfaces
A lazy loading ghost object cannot proxy an interface directly, as it operates directly around the state of an object. Use a
[Virtual Proxy](lazy-loading-value-holder.md) for that instead.
## Tuning performance for production
See [Tuning ProxyManager for Production](tuning-for-production.md).
docs/lazy-loading-value-holder.md 0000644 00000015221 13721511157 0013001 0 ustar 00 ---
title: Lazy Loading Value Holder Proxy
---
# Lazy Loading Value Holder Proxy
A lazy loading value holder proxy is a virtual proxy that wraps and lazily initializes a "real" instance of the proxied class.
## What is lazy loading?
In pseudo-code, [lazy loading](http://www.martinfowler.com/eaaCatalog/lazyLoad.html) looks like the following:
```php
class MyObjectProxy
{
private $wrapped;
public function doFoo()
{
$this->init();
return $this->wrapped->doFoo();
}
private function init()
{
if (null === $this->wrapped) {
$this->wrapped = new MyObject();
}
}
}
```
This code is problematic and adds complexity that makes your unit tests' code even worse.
Also, this kind of usage often ends up in coupling your code with a particular
[Dependency Injection Container](http://martinfowler.com/articles/injection.html) or a framework that fetches dependencies
for you. That way, further complexity is introduced, and some problems related with service location raise, as explained
[in this article](http://ocramius.github.com/blog/zf2-and-symfony-service-proxies-with-doctrine-proxies/).
Lazy loading value holders abstract this logic for you, hiding your complex, slow, performance-impacting objects behind tiny
wrappers that have their same API, and that get initialized at first usage.
## When do I use a lazy value holder?
You usually need a lazy value holder in cases where the following applies:
* your object takes a lot of time and memory to be initialized (with all dependencies)
* your object is not always used, and the instantiation overhead is avoidable
## Usage examples
*ProxyManager* provides a factory that eases instantiation of lazy loading
value holders. To use it, follow these steps:
Firstly, define your object's logic without taking care of lazy loading:
```php
namespace MyApp;
class HeavyComplexObject
{
public function __construct()
{
// just write your business logic
// don't worry about how heavy initialization of this will be!
}
public function doFoo() {
echo 'OK!';
}
}
```
Then use the proxy manager to create a lazy version of the object (as a proxy):
```php
namespace MyApp;
use ProxyManager\Factory\LazyLoadingValueHolderFactory;
use ProxyManager\Proxy\LazyLoadingInterface;
require_once __DIR__ . '/vendor/autoload.php';
$factory = new LazyLoadingValueHolderFactory();
$initializer = function (& $wrappedObject, LazyLoadingInterface $proxy, $method, array $parameters, & $initializer) {
$initializer = null; // disable initialization
$wrappedObject = new HeavyComplexObject(); // fill your object with values here
return true; // confirm that initialization occurred correctly
};
$proxy = $factory->createProxy('MyApp\HeavyComplexObject', $initializer);
```
You can now use your object as before:
```php
// this will just work as before
$proxy->doFoo(); // OK!
```
## Lazy Initialization
As you can see, we use a closure to handle lazy initialization of the proxy instance at runtime. The initializer closure
signature should be as following:
```php
/**
* @var object $wrappedObject the instance (passed by reference) of the wrapped object,
* set it to your real object
* @var object $proxy the instance proxy that is being initialized
* @var string $method the name of the method that triggered lazy initialization
* @var array $parameters an ordered list of parameters passed to the method that
* triggered initialization, indexed by parameter name
* @var Closure $initializer a reference to the property that is the initializer for the
* proxy. Set it to null to disable further initialization
*
* @return bool true on success
*/
$initializer = function (& $wrappedObject, $proxy, $method, array $parameters, & $initializer) {};
```
The initializer closure should usually be coded like following:
```php
$initializer = function (& $wrappedObject, $proxy, $method, array $parameters, & $initializer) {
$newlyCreatedObject = new Foo(); // instantiation logic
$newlyCreatedObject->setBar('baz'); // instantiation logic
$newlyCreatedObject->setBat('bam'); // instantiation logic
$wrappedObject = $newlyCreatedObject; // set wrapped object in the proxy
$initializer = null; // disable initializer
return true; // report success
};
```
The
[`ProxyManager\Factory\LazyLoadingValueHolderFactory`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Factory/LazyLoadingValueHolderFactory.php)
produces proxies that implement both the
[`ProxyManager\Proxy\ValueHolderInterface`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Proxy/ValueHolderInterface.php)
and the
[`ProxyManager\Proxy\LazyLoadingInterface`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Proxy/LazyLoadingInterface.php).
At any point in time, you can set a new initializer for the proxy:
```php
$proxy->setProxyInitializer($initializer);
```
In your initializer, you currently **MUST** turn off any further initialization:
```php
$proxy->setProxyInitializer(null);
```
or
```php
$initializer = null; // if you use the initializer by reference
```
## Triggering Initialization
A lazy loading proxy is initialized whenever you access any property or method of it. Any of the following interactions would
trigger lazy initialization:
```php
// calling a method
$proxy->someMethod();
// reading a property
echo $proxy->someProperty;
// writing a property
$proxy->someProperty = 'foo';
// checking for existence of a property
isset($proxy->someProperty);
// removing a property
unset($proxy->someProperty);
// cloning the entire proxy
clone $proxy;
// serializing the proxy
$unserialized = serialize(unserialize($proxy));
```
Remember to call `$proxy->setProxyInitializer(null);` to disable initialization of your proxy, or it will happen more than
once.
## Proxying interfaces
You can also generate proxies from an interface FQCN. When you proxy an interface, you will only be able to access the
methods defined by the interface itself, even if the `wrappedObject` implements more methods. This will save some memory
since the proxy will not contain useless inherited properties.
## Known limitations
* methods using `func_get_args()`, `func_get_arg()` and `func_num_arg()` will not function properly for parameters that are
not part of the proxied object interface: use
[variadic arguments](http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list) instead.
## Tuning performance for production
See [Tuning ProxyManager for Production](tuning-for-production.md).
docs/null-object.md 0000644 00000005671 13721511157 0010250 0 ustar 00 ---
title: Null Object Proxy
---
# Null Object Proxy
A Null Object proxy is a [null object pattern](http://en.wikipedia.org/wiki/Null_Object_pattern) implementation.
The proxy factory creates a new object with defined neutral behaviour based on another object, class name or interface.
## What is null object proxy?
In your application, when you cannot return the object related to the request, the consumer of the model must check for the
return value and handle the failing condition gracefully, thus generating an explosion of conditionals throughout your code.
Fortunately, this seemingly-tangled situation can be simplified by creating a polymorphic implementation of the domain object,
which would implement the same interface as one of the objects in question, only that its methods would not do anything,
therefore offloading client code from doing repetitive checks for ugly null values when the operation is executed.
## Usage examples
```php
class UserMapper
{
private $adapter;
public function __construct(DatabaseAdapterInterface $adapter) {
$this->adapter = $adapter;
}
public function fetchById($id) {
$this->adapter->select('users', ['id' => $id]);
if (!$row = $this->adapter->fetch()) {
return null;
}
return $this->createUser($row);
}
private function createUser(array $row) {
$user = new Entity\User($row['name'], $row['email']);
$user->setId($row['id']);
return $user;
}
}
```
If you want to remove conditionals from client code, you need to have a version of the entity conforming to the corresponding
interface. With the Null Object Proxy, you can build this object :
```php
$factory = new \ProxyManager\Factory\NullObjectFactory();
$nullUser = $factory->createProxy('Entity\User');
var_dump($nullUser->getName()); // empty return
```
You can now return a valid entity :
```php
class UserMapper
{
private $adapter;
public function __construct(DatabaseAdapterInterface $adapter) {
$this->adapter = $adapter;
}
public function fetchById($id) {
$this->adapter->select('users', ['id' => $id]);
return $this->createUser($this->adapter->fetch());
}
private function createUser($row) {
if (!$row) {
$factory = new \ProxyManager\Factory\NullObjectFactory();
return $factory->createProxy('Entity\User');
}
$user = new Entity\User($row['name'], $row['email']);
$user->setId($row['id']);
return $user;
}
}
```
## Proxying interfaces
You can also generate proxies from an interface FQCN. By proxying an interface, you will only be able to access the methods
defined by the interface itself, and like with the object, the methods are empty.
## Tuning performance for production
See [Tuning ProxyManager for Production](tuning-for-production.md).
docs/remote-object.md 0000644 00000005457 13721511157 0010573 0 ustar 00 ---
title: Remote Object Proxy
---
# Remote Object Proxy
The remote object implementation is a mechanism that enables a local object to control another object on another server. Each
call method on the local object will do a network call to get information or execute operations on the remote object.
## What is remote object proxy?
A remote object is based on an interface. The remote interface defines the API that a consumer can call. This interface must
be implemented both by the client and the RPC server.
## Adapters
Laminas's RPC components (XmlRpc, JsonRpc & Soap) can be used with the remote object. You will need to require the one
you need via composer:
```sh
$ php composer.phar require laminas/laminas-xmlrpc:2.*
$ php composer.phar require laminas/laminas-json:2.*
$ php composer.phar require laminas/laminas-soap:2.*
```
ProxyManager comes with 3 adapters:
* `ProxyManager\Factory\RemoteObject\Adapter\XmlRpc`
* `ProxyManager\Factory\RemoteObject\Adapter\JsonRpc`
* `ProxyManager\Factory\RemoteObject\Adapter\Soap`
## Usage examples
RPC server side code (`xmlrpc.php` in your local webroot):
```php
interface FooServiceInterface
{
public function foo();
}
class Foo implements FooServiceInterface
{
/**
* Foo function
* @return string
*/
public function foo()
{
return 'bar remote';
}
}
$server = new Laminas\XmlRpc\Server();
$server->setClass('Foo', 'FooServiceInterface'); // my FooServiceInterface implementation
$server->handle();
```
Client side code (proxy) :
```php
interface FooServiceInterface
{
public function foo();
}
$factory = new \ProxyManager\Factory\RemoteObjectFactory(
new \ProxyManager\Factory\RemoteObject\Adapter\XmlRpc(
new \Laminas\XmlRpc\Client('https://localhost/xmlrpc.php')
)
);
$proxy = $factory->createProxy('FooServiceInterface');
var_dump($proxy->foo()); // "bar remote"
```
## Implementing custom adapters
Your adapters must implement `ProxyManager\Factory\RemoteObject\AdapterInterface`:
```php
interface AdapterInterface
{
/**
* Call remote object
*
* @param string $wrappedClass
* @param string $method
* @param array $params
*
* @return mixed
*/
public function call($wrappedClass, $method, array $params = []);
}
```
To create your implementation (for RESTful web services, for example), pass your adapter instance to your factory at
construction time.
## Known limitations
* methods using `func_get_args()`, `func_get_arg()` and `func_num_arg()` will not function properly for parameters that are
not part of the proxied object interface: use
[variadic arguments](http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list) instead.
## Tuning performance for production
See [Tuning ProxyManager for Production](tuning-for-production.md).
docs/tuning-for-production.md 0000644 00000003254 13721511157 0012301 0 ustar 00 ---
title: Tuning the ProxyManager for production
---
## Tuning the ProxyManager for production
By default, all proxy factories generate the required proxy classes at runtime.
Proxy generation causes I/O operations and uses significant amounts of reflection, so be sure to have generated all of your
proxies **before deploying your code on a live system**, or you may experience poor performance.
To generate proxies and store them as files, you need to use the `FileWriterGeneratorStrategy` by configuring ProxyManager.
The files generated in the directory will be needed to autoload the proxies.
You can configure ProxyManager so that it will try autoloading the proxies first. Generating them en-masse is not yet
implemented:
```php
$config = new \ProxyManager\Configuration();
// generate the proxies and store them as files
$fileLocator = new \ProxyManager\FileLocator\FileLocator(__DIR__.'/my/generated/classes/cache/dir');
$config->setGeneratorStrategy(new \ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy($fileLocator));
// set the directory to read the generated proxies from
$config->setProxiesTargetDir(__DIR__ . '/my/generated/classes/cache/dir');
// then register the autoloader
spl_autoload_register($config->getProxyAutoloader());
// pass the configuration to proxymanager factory
$factory = new ProxyManager\Factory\LazyLoadingValueHolderFactory($config);
```
You can also generate a classmap with all your proxy classes in it.
Please note that all the currently implemented `ProxyManager\Factory\*` classes accept a `ProxyManager\Configuration` object
as an optional constructor parameter. This allows for fine-tuning of ProxyManager according to your needs.
examples/access-interceptor-scope-localizer.php 0000644 00000002664 13721511157 0015774 0 ustar 00 counter += 1;
return $this;
}
}
(static function () : void {
$factory = new AccessInterceptorScopeLocalizerFactory();
$foo = new FluentCounter();
$proxy = $factory->createProxy(
$foo,
[
'fluentMethod' => static function (AccessInterceptorInterface $proxy, FluentCounter $realInstance) : void {
echo "pre-fluentMethod #{$realInstance->counter}!\n";
},
],
[
'fluentMethod' => static function (AccessInterceptorInterface $proxy, FluentCounter $realInstance) : void {
echo "post-fluentMethod #{$realInstance->counter}!\n";
},
]
);
$proxy->fluentMethod()->fluentMethod()->fluentMethod()->fluentMethod();
echo 'The proxy counter is now at ' . $proxy->counter . "\n";
echo 'The real instance counter is now at ' . $foo->counter . "\n";
})();
examples/ghost-object-skipped-properties.php 0000644 00000002534 13721511157 0015321 0 ustar 00 id;
}
public function getUsername() : ?string
{
return $this->username;
}
}
(static function () : void {
$proxy = (new LazyLoadingGhostFactory())->createProxy(
User::class,
static function (
GhostObjectInterface $proxy,
string $method,
array $parameters,
?Closure & $initializer,
array $properties
) {
$initializer = null;
var_dump('Triggered lazy-loading!');
$properties["\0ProxyManager\\Example\\GhostObjectSkippedProperties\\User\0username"] = 'Ocramius';
return true;
},
[
'skippedProperties' => ["\0User\0id"],
]
);
$idReflection = new ReflectionProperty(User::class, 'id');
$idReflection->setAccessible(true);
$idReflection->setValue($proxy, 123);
var_dump($proxy->getId());
var_dump($proxy->getUsername());
})();
examples/ghost-object.php 0000644 00000002634 13721511157 0011473 0 ustar 00 foo = $foo;
}
public function getFoo() : string
{
return $this->foo;
}
}
(static function () : void {
$startTime = microtime(true);
$factory = new LazyLoadingGhostFactory();
$i = 0;
do {
$proxy = $factory->createProxy(
Foo::class,
function (
GhostObjectInterface $proxy,
string $method,
array $parameters,
?Closure & $initializer,
array $properties
) : bool {
$initializer = null;
$properties["\0ProxyManager\\Example\\GhostObject\\Foo\0foo"] = 'Hello World!';
return true;
}
);
$i += 1;
} while ($i < 1000);
var_dump('time after 1000 instantiations: ' . (microtime(true) - $startTime));
echo $proxy->getFoo() . "\n";
var_dump('time after single call to doFoo: ' . (microtime(true) - $startTime));
})();
examples/remote-proxy.php 0000644 00000002161 13721511157 0011550 0 ustar 00 createProxy(Foo::class);
try {
var_dump($proxy->bar()); // bar remote !
} catch (RuntimeException $error) {
echo "To run this example, please following before:\n\n\$ php -S localhost:9876 -t \"" . __DIR__ . "\"\n";
exit(2);
}
})();
examples/remote-proxy/remote-proxy-server.php 0000644 00000000652 13721511157 0015531 0 ustar 00 setClass(new Foo(), 'Foo');
$server->setReturnResponse(false);
$server->handle();
})();
examples/smart-reference.php 0000644 00000001260 13721511157 0012157 0 ustar 00 createProxy(
new Foo(),
[
'doFoo' => function () : void {
echo "pre-foo!\n";
},
],
[
'doFoo' => function () : void {
echo "post-foo!\n";
},
]
);
$proxy->doFoo();
})();
examples/virtual-proxy.php 0000644 00000002112 13721511157 0011737 0 ustar 00 createProxy(
Foo::class,
static function (
?object & $wrappedObject, ?object $proxy, string $method, array $parameters, ?Closure & $initializer
) {
$initializer = null;
$wrappedObject = new Foo();
return true;
}
);
$i += 1;
} while ($i < 1000);
var_dump('time after 1000 instantiations: ' . (microtime(true) - $startTime));
$proxy->doFoo();
var_dump('time after single call to doFoo: ' . (microtime(true) - $startTime));
})();
proxy-manager.svg 0000644 00000033521 13721511157 0010065 0 ustar 00
src/ProxyManager/Autoloader/Autoloader.php 0000644 00000002166 13721511157 0014666 0 ustar 00 fileLocator = $fileLocator;
$this->classNameInflector = $classNameInflector;
}
public function __invoke(string $className): bool
{
if (class_exists($className, false) || ! $this->classNameInflector->isProxyClassName($className)) {
return false;
}
$file = $this->fileLocator->getProxyFileName($className);
if (! file_exists($file)) {
return false;
}
/* @noinspection PhpIncludeInspection */
/* @noinspection UsingInclusionOnceReturnValueInspection */
return (bool) require_once $file;
}
}
src/ProxyManager/Autoloader/AutoloaderInterface.php 0000644 00000000622 13721511157 0016502 0 ustar 00 proxyAutoloader = $proxyAutoloader;
}
public function getProxyAutoloader(): AutoloaderInterface
{
return $this->proxyAutoloader
?? $this->proxyAutoloader = new Autoloader(
new FileLocator($this->getProxiesTargetDir()),
$this->getClassNameInflector()
);
}
public function setProxiesNamespace(string $proxiesNamespace): void
{
$this->proxiesNamespace = $proxiesNamespace;
}
public function getProxiesNamespace(): string
{
return $this->proxiesNamespace;
}
public function setProxiesTargetDir(string $proxiesTargetDir): void
{
$this->proxiesTargetDir = $proxiesTargetDir;
}
public function getProxiesTargetDir(): string
{
return $this->proxiesTargetDir
?? $this->proxiesTargetDir = sys_get_temp_dir();
}
public function setGeneratorStrategy(GeneratorStrategyInterface $generatorStrategy): void
{
$this->generatorStrategy = $generatorStrategy;
}
public function getGeneratorStrategy(): GeneratorStrategyInterface
{
return $this->generatorStrategy
?? $this->generatorStrategy = new EvaluatingGeneratorStrategy();
}
public function setClassNameInflector(ClassNameInflectorInterface $classNameInflector): void
{
$this->classNameInflector = $classNameInflector;
}
public function getClassNameInflector(): ClassNameInflectorInterface
{
return $this->classNameInflector
?? $this->classNameInflector = new ClassNameInflector($this->getProxiesNamespace());
}
public function setSignatureGenerator(SignatureGeneratorInterface $signatureGenerator): void
{
$this->signatureGenerator = $signatureGenerator;
}
public function getSignatureGenerator(): SignatureGeneratorInterface
{
return $this->signatureGenerator
?? $this->signatureGenerator = new SignatureGenerator();
}
public function setSignatureChecker(SignatureCheckerInterface $signatureChecker): void
{
$this->signatureChecker = $signatureChecker;
}
public function getSignatureChecker(): SignatureCheckerInterface
{
return $this->signatureChecker
?? $this->signatureChecker = new SignatureChecker($this->getSignatureGenerator());
}
public function setClassSignatureGenerator(ClassSignatureGeneratorInterface $classSignatureGenerator): void
{
$this->classSignatureGenerator = $classSignatureGenerator;
}
public function getClassSignatureGenerator(): ClassSignatureGeneratorInterface
{
return $this->classSignatureGenerator
?? $this->classSignatureGenerator = new ClassSignatureGenerator($this->getSignatureGenerator());
}
}
src/ProxyManager/Exception/DisabledMethodException.php 0000644 00000000717 13721511157 0017155 0 ustar 00 getMessage(), 0, $previous);
}
}
src/ProxyManager/Exception/InvalidProxiedClassException.php 0000644 00000003302 13721511157 0020205 0 ustar 00 getName()));
}
public static function finalClassNotSupported(ReflectionClass $reflection): self
{
return new self(sprintf('Provided class "%s" is final and cannot be proxied', $reflection->getName()));
}
public static function abstractProtectedMethodsNotSupported(ReflectionClass $reflection): self
{
return new self(sprintf(
'Provided class "%s" has following protected abstract methods, and therefore cannot be proxied:' . "\n%s",
$reflection->getName(),
implode(
"\n",
array_map(
static function (ReflectionMethod $reflectionMethod): string {
return $reflectionMethod->getDeclaringClass()->getName() . '::' . $reflectionMethod->getName();
},
array_filter(
$reflection->getMethods(),
static function (ReflectionMethod $method): bool {
return $method->isAbstract() && $method->isProtected();
}
)
)
)
));
}
}
src/ProxyManager/Exception/InvalidProxyDirectoryException.php 0000644 00000000676 13721511157 0020626 0 ustar 00 getName(),
$property->getDeclaringClass()->getName()
)
);
}
public static function nonReferenceableLocalizedReflectionProperties(
ReflectionClass $class,
Properties $properties
): self {
return new self(sprintf(
'Cannot create references for following properties of class %s: %s',
$class->getName(),
implode(', ', array_map(static function (ReflectionProperty $property): string {
return $property->getName();
}, $properties->getInstanceProperties()))
));
}
}
src/ProxyManager/Factory/AbstractBaseFactory.php 0000644 00000007620 13721511157 0015765 0 ustar 00
* @psalm-var array
*/
private array $checkedClasses = [];
public function __construct(?Configuration $configuration = null)
{
$this->configuration = $configuration ?: new Configuration();
}
/**
* Generate a proxy from a class name
*
* @param array $proxyOptions
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
* @throws OutOfBoundsException
*
* @psalm-template RealObjectType of object
*
* @psalm-param class-string $className
*
* @psalm-return class-string
*/
protected function generateProxy(string $className, array $proxyOptions = []): string
{
if (array_key_exists($className, $this->checkedClasses)) {
$generatedClassName = $this->checkedClasses[$className];
assert(is_a($generatedClassName, $className, true));
return $generatedClassName;
}
$proxyParameters = [
'className' => $className,
'factory' => static::class,
'proxyManagerVersion' => Version::getVersion(),
'proxyOptions' => $proxyOptions,
];
$proxyClassName = $this
->configuration
->getClassNameInflector()
->getProxyClassName($className, $proxyParameters);
if (! class_exists($proxyClassName)) {
$this->generateProxyClass(
$proxyClassName,
$className,
$proxyParameters,
$proxyOptions
);
}
$this
->configuration
->getSignatureChecker()
->checkSignature(new ReflectionClass($proxyClassName), $proxyParameters);
return $this->checkedClasses[$className] = $proxyClassName;
}
abstract protected function getGenerator(): ProxyGeneratorInterface;
/**
* Generates the provided `$proxyClassName` from the given `$className` and `$proxyParameters`
*
* @param array $proxyParameters
* @param array $proxyOptions
*
* @psalm-param class-string $proxyClassName
* @psalm-param class-string $className
*/
private function generateProxyClass(
string $proxyClassName,
string $className,
array $proxyParameters,
array $proxyOptions = []
): void {
$className = $this->configuration->getClassNameInflector()->getUserClassName($className);
$phpClass = new ClassGenerator($proxyClassName);
/** @psalm-suppress TooManyArguments - generator interface was not updated due to BC compliance */
$this->getGenerator()->generate(new ReflectionClass($className), $phpClass, $proxyOptions);
$phpClass = $this->configuration->getClassSignatureGenerator()->addSignature($phpClass, $proxyParameters);
/** @psalm-suppress TooManyArguments - generator interface was not updated due to BC compliance */
$this->configuration->getGeneratorStrategy()->generate($phpClass, $proxyOptions);
$autoloader = $this->configuration->getProxyAutoloader();
$autoloader($proxyClassName);
}
}
src/ProxyManager/Factory/AccessInterceptorScopeLocalizerFactory.php 0000644 00000006057 13721511157 0021711 0 ustar 00 generator = new AccessInterceptorScopeLocalizerGenerator();
}
/**
* @param object $instance the object to be localized within the access interceptor
* @param array $prefixInterceptors an array (indexed by method name) of interceptor closures to be called
* before method logic is executed
* @param array $suffixInterceptors an array (indexed by method name) of interceptor closures to be called
* after method logic is executed
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
* @throws OutOfBoundsException
*
* @psalm-template RealObjectType of object
*
* @psalm-param RealObjectType $instance
* @psalm-param array=,
* RealObjectType=,
* string=,
* array=,
* bool=
* ) : mixed> $prefixInterceptors
* @psalm-param array=,
* RealObjectType=,
* string=,
* array=,
* mixed=,
* bool=
* ) : mixed> $suffixInterceptors
*
* @psalm-return RealObjectType&AccessInterceptorInterface
*
* @psalm-suppress MixedInferredReturnType We ignore type checks here, since `staticProxyConstructor` is not
* interfaced (by design)
*/
public function createProxy(
object $instance,
array $prefixInterceptors = [],
array $suffixInterceptors = []
): AccessInterceptorInterface {
$proxyClassName = $this->generateProxy(get_class($instance));
/**
* We ignore type checks here, since `staticProxyConstructor` is not interfaced (by design)
*
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedReturnStatement
*/
return $proxyClassName::staticProxyConstructor($instance, $prefixInterceptors, $suffixInterceptors);
}
protected function getGenerator(): ProxyGeneratorInterface
{
return $this->generator;
}
}
src/ProxyManager/Factory/AccessInterceptorValueHolderFactory.php 0000644 00000006356 13721511157 0021207 0 ustar 00 generator = new AccessInterceptorValueHolderGenerator();
}
/**
* @param object $instance the object to be wrapped within the value holder
* @param array $prefixInterceptors an array (indexed by method name) of interceptor closures to be called
* before method logic is executed
* @param array $suffixInterceptors an array (indexed by method name) of interceptor closures to be called
* after method logic is executed
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
* @throws OutOfBoundsException
*
* @psalm-template RealObjectType of object
*
* @psalm-param RealObjectType $instance
* @psalm-param array=,
* RealObjectType=,
* string=,
* array=,
* bool=
* ) : mixed> $prefixInterceptors
* @psalm-param array=,
* RealObjectType=,
* string=,
* array=,
* mixed=,
* bool=
* ) : mixed> $suffixInterceptors
*
* @psalm-return RealObjectType&AccessInterceptorInterface&ValueHolderInterface&AccessInterceptorValueHolderInterface
*
* @psalm-suppress MixedInferredReturnType We ignore type checks here, since `staticProxyConstructor` is not
* interfaced (by design)
*/
public function createProxy(
object $instance,
array $prefixInterceptors = [],
array $suffixInterceptors = []
): AccessInterceptorValueHolderInterface {
$proxyClassName = $this->generateProxy(get_class($instance));
/**
* We ignore type checks here, since `staticProxyConstructor` is not interfaced (by design)
*
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedReturnStatement
*/
return $proxyClassName::staticProxyConstructor($instance, $prefixInterceptors, $suffixInterceptors);
}
protected function getGenerator(): ProxyGeneratorInterface
{
return $this->generator;
}
}
src/ProxyManager/Factory/LazyLoadingGhostFactory.php 0000644 00000010710 13721511157 0016643 0 ustar 00 generator = new LazyLoadingGhostGenerator();
}
protected function getGenerator(): ProxyGeneratorInterface
{
return $this->generator;
}
/**
* Creates a new lazy proxy instance of the given class with
* the given initializer
*
* Please refer to the following documentation when using this method:
*
* @link https://github.com/Ocramius/ProxyManager/blob/master/docs/lazy-loading-ghost-object.md
*
* @param string $className name of the class to be proxied
* @param Closure $initializer initializer to be passed to the proxy. The initializer closure should have following
* signature:
*
*
* $initializer = function (
* GhostObjectInterface $proxy,
* string $method,
* array $parameters,
* & $initializer,
* array $properties
* ) {};
*
*
* Where:
* - $proxy is the proxy instance on which the initializer is acting
* - $method is the name of the method that triggered the lazy initialization
* - $parameters are the parameters that were passed to $method
* - $initializer by-ref initializer - should be assigned null in the initializer body
* - $properties a by-ref map of the properties of the object, indexed by PHP
* internal property name. Assign values to it to initialize the
* object state
* @param mixed[] $proxyOptions a set of options to be used when generating the proxy. Currently supports only
* key "skippedProperties", which allows to skip lazy-loading of some properties.
* "skippedProperties" is a string[], containing a list of properties referenced
* via PHP's internal property name (i.e. "\0ClassName\0propertyName")
*
* @throws MissingSignatureException
* @throws InvalidSignatureException
* @throws OutOfBoundsException
*
* @psalm-template RealObjectType as object
*
* @psalm-param class-string $className
* @psalm-param Closure(
* RealObjectType&GhostObjectInterface=,
* string=,
* array=,
* ?Closure=,
* array=
* ) : bool $initializer
* @psalm-param array{skippedProperties?: array} $proxyOptions
*
* @psalm-return RealObjectType&GhostObjectInterface
*
* @psalm-suppress MixedInferredReturnType We ignore type checks here, since `staticProxyConstructor` is not
* interfaced (by design)
*/
public function createProxy(
string $className,
Closure $initializer,
array $proxyOptions = []
): GhostObjectInterface {
$proxyClassName = $this->generateProxy($className, $proxyOptions);
/**
* We ignore type checks here, since `staticProxyConstructor` is not interfaced (by design)
*
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedReturnStatement
*/
return $proxyClassName::staticProxyConstructor($initializer);
}
}
src/ProxyManager/Factory/LazyLoadingValueHolderFactory.php 0000644 00000004034 13721511157 0017773 0 ustar 00 generator = new LazyLoadingValueHolderGenerator();
}
/**
* @param array $proxyOptions
*
* @psalm-template RealObjectType of object
*
* @psalm-param class-string $className
* @psalm-param Closure(
* RealObjectType|null=,
* RealObjectType&ValueHolderInterface&VirtualProxyInterface=,
* string=,
* array=,
* ?Closure=
* ) : bool $initializer
*
* @psalm-return RealObjectType&ValueHolderInterface&VirtualProxyInterface
*
* @psalm-suppress MixedInferredReturnType We ignore type checks here, since `staticProxyConstructor` is not
* interfaced (by design)
*/
public function createProxy(
string $className,
Closure $initializer,
array $proxyOptions = []
): VirtualProxyInterface {
$proxyClassName = $this->generateProxy($className, $proxyOptions);
/**
* We ignore type checks here, since `staticProxyConstructor` is not interfaced (by design)
*
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedReturnStatement
*/
return $proxyClassName::staticProxyConstructor($initializer);
}
protected function getGenerator(): ProxyGeneratorInterface
{
return $this->generator;
}
}
src/ProxyManager/Factory/NullObjectFactory.php 0000644 00000004077 13721511157 0015473 0 ustar 00 generator = new NullObjectGenerator();
}
/**
* @param object|string $instanceOrClassName the object to be wrapped or interface to transform to null object
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
* @throws OutOfBoundsException
*
* @psalm-template RealObjectType of object
*
* @psalm-param RealObjectType|class-string $instanceOrClassName
*
* @psalm-return RealObjectType&NullObjectInterface
*
* @psalm-suppress MixedInferredReturnType We ignore type checks here, since `staticProxyConstructor` is not
* interfaced (by design)
*/
public function createProxy($instanceOrClassName): NullObjectInterface
{
$className = is_object($instanceOrClassName) ? get_class($instanceOrClassName) : $instanceOrClassName;
$proxyClassName = $this->generateProxy($className);
/**
* We ignore type checks here, since `staticProxyConstructor` is not interfaced (by design)
*
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedReturnStatement
*/
return $proxyClassName::staticProxyConstructor();
}
protected function getGenerator(): ProxyGeneratorInterface
{
return $this->generator;
}
}
src/ProxyManager/Factory/RemoteObject/Adapter/BaseAdapter.php 0000644 00000002355 13721511157 0020214 0 ustar 00
*/
protected array $map = [];
/**
* Constructor
*
* @param array $map map of service names to their aliases
*/
public function __construct(Client $client, array $map = [])
{
$this->client = $client;
$this->map = $map;
}
/**
* {@inheritDoc}
*/
public function call(string $wrappedClass, string $method, array $params = [])
{
$serviceName = $this->getServiceName($wrappedClass, $method);
if (array_key_exists($serviceName, $this->map)) {
$serviceName = $this->map[$serviceName];
}
return $this->client->call($serviceName, $params);
}
/**
* Get the service name will be used by the adapter
*/
abstract protected function getServiceName(string $wrappedClass, string $method): string;
}
src/ProxyManager/Factory/RemoteObject/Adapter/JsonRpc.php 0000644 00000000465 13721511157 0017417 0 ustar 00 $params
*
* @return mixed
*/
public function call(string $wrappedClass, string $method, array $params = []);
}
src/ProxyManager/Factory/RemoteObjectFactory.php 0000644 00000004546 13721511157 0016015 0 ustar 00 adapter = $adapter;
$this->generator = new RemoteObjectGenerator();
}
/**
* @param string|object $instanceOrClassName
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
* @throws OutOfBoundsException
*
* @psalm-template RealObjectType of object
*
* @psalm-param RealObjectType|class-string $instanceOrClassName
*
* @psalm-return RealObjectType&RemoteObjectInterface
*
* @psalm-suppress MixedInferredReturnType We ignore type checks here, since `staticProxyConstructor` is not
* interfaced (by design)
*/
public function createProxy($instanceOrClassName): RemoteObjectInterface
{
$proxyClassName = $this->generateProxy(
is_object($instanceOrClassName) ? get_class($instanceOrClassName) : $instanceOrClassName
);
/**
* We ignore type checks here, since `staticProxyConstructor` is not interfaced (by design)
*
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedReturnStatement
*/
return $proxyClassName::staticProxyConstructor($this->adapter);
}
protected function getGenerator(): ProxyGeneratorInterface
{
return $this->generator ?? $this->generator = new RemoteObjectGenerator();
}
}
src/ProxyManager/FileLocator/FileLocator.php 0000644 00000001545 13721511157 0015076 0 ustar 00 proxiesDirectory = $absolutePath;
}
public function getProxyFileName(string $className): string
{
return $this->proxiesDirectory . DIRECTORY_SEPARATOR . str_replace('\\', '', $className) . '.php';
}
}
src/ProxyManager/FileLocator/FileLocatorInterface.php 0000644 00000000465 13721511157 0016717 0 ustar 00 $interfaces
*
* @psalm-suppress MoreSpecificImplementedParamType parent interface does not specify type of array values
*/
public function setImplementedInterfaces(array $interfaces): ZendClassGenerator
{
return parent::setImplementedInterfaces(array_map(
static function (string $interface): string {
return '\\' . trim($interface, '\\');
},
$interfaces
));
}
}
src/ProxyManager/Generator/MagicMethodGenerator.php 0000644 00000001337 13721511157 0016445 0 ustar 00 setReturnsReference(strtolower($name) === '__get');
if (! $originalClass->hasMethod($name)) {
return;
}
$this->setReturnsReference($originalClass->getMethod($name)->returnsReference());
}
}
src/ProxyManager/Generator/MethodGenerator.php 0000644 00000002100 13721511157 0015471 0 ustar 00 setInterface(false);
$method->setBody('');
return $method;
}
/**
* {@inheritDoc} override needed to specify type in more detail
*/
public function getDocBlock(): ?DocBlockGenerator
{
return parent::getDocBlock();
}
/**
* {@inheritDoc} override needed to specify type in more detail
*/
public function getSourceContent(): ?string
{
return parent::getSourceContent();
}
}
src/ProxyManager/Generator/Util/ClassGeneratorUtils.php 0000644 00000001343 13721511157 0017264 0 ustar 00 getName();
if ($originalClass->hasMethod($methodName) && $originalClass->getMethod($methodName)->isFinal()) {
return false;
}
$classGenerator->addMethodFromGenerator($generatedMethod);
return true;
}
}
src/ProxyManager/Generator/Util/IdentifierSuffixer.php 0000644 00000002415 13721511157 0017126 0 ustar 00 getReturnType();
$originalReturnTypeName = $originalReturnType === null
? null
: $originalReturnType->getName();
if ($originalReturnTypeName === 'void') {
return $returnedValueExpression . ";\nreturn;";
}
return 'return ' . $returnedValueExpression . ';';
}
}
src/ProxyManager/Generator/Util/UniqueIdentifierGenerator.php 0000644 00000001760 13721511157 0020452 0 ustar 00 generate();
}
}
src/ProxyManager/GeneratorStrategy/EvaluatingGeneratorStrategy.php 0000644 00000002626 13721511157 0021633 0 ustar 00 canEval = ! ini_get('suhosin.executor.disable_eval');
// @codeCoverageIgnoreEnd
}
/**
* Evaluates the generated code before returning it
*
* {@inheritDoc}
*/
public function generate(ClassGenerator $classGenerator): string
{
$code = $classGenerator->generate();
assert(is_string($code));
// @codeCoverageIgnoreStart
if (! $this->canEval) {
$fileName = __DIR__ . '/EvaluatingGeneratorStrategy.php.tmp';
FileWriter::writeFile($fileName, "fileLocator = $fileLocator;
$this->emptyErrorHandler = static function (): void {
};
}
/**
* Write generated code to disk and return the class code
*
* {@inheritDoc}
*
* @throws FileNotWritableException
*/
public function generate(ClassGenerator $classGenerator): string
{
$generatedCode = $classGenerator->generate();
assert(is_string($generatedCode));
$className = $classGenerator->getNamespaceName() . '\\' . $classGenerator->getName();
$fileName = $this->fileLocator->getProxyFileName($className);
set_error_handler($this->emptyErrorHandler);
try {
FileWriter::writeFile($fileName, "proxyNamespace = $proxyNamespace;
$this->proxyMarker = '\\' . self::PROXY_MARKER . '\\';
$this->proxyMarkerLength = strlen($this->proxyMarker);
$this->parameterHasher = new ParameterHasher();
}
/**
* {@inheritDoc}
*
* @psalm-suppress MoreSpecificReturnType we ignore these issues because classes may not have been loaded yet
*/
public function getUserClassName(string $className): string
{
$className = ltrim($className, '\\');
$position = strrpos($className, $this->proxyMarker);
if (! is_int($position)) {
/** @psalm-suppress LessSpecificReturnStatement */
return $className;
}
/** @psalm-suppress LessSpecificReturnStatement */
return substr(
$className,
$this->proxyMarkerLength + $position,
(int) strrpos($className, '\\') - ($position + $this->proxyMarkerLength)
);
}
/**
* {@inheritDoc}
*
* @psalm-suppress MoreSpecificReturnType we ignore these issues because classes may not have been loaded yet
*/
public function getProxyClassName(string $className, array $options = []): string
{
/** @psalm-suppress LessSpecificReturnStatement */
return $this->proxyNamespace
. $this->proxyMarker
. $this->getUserClassName($className)
. '\\Generated' . $this->parameterHasher->hashParameters($options);
}
public function isProxyClassName(string $className): bool
{
return strrpos($className, $this->proxyMarker) !== false;
}
}
src/ProxyManager/Inflector/ClassNameInflectorInterface.php 0000644 00000003021 13721511157 0017741 0 ustar 00 |class-string> $className
* @psalm-return class-string
*/
public function getUserClassName(string $className): string;
/**
* Retrieve the class name of the proxy for the given user-defined class name
*
* @param array $options arbitrary options to be used for the generated class name
*
* @psalm-template RealClassName of object
*
* @psalm-param class-string|class-string> $className
*
* @psalm-return class-string
*/
public function getProxyClassName(string $className, array $options = []): string;
/**
* Retrieve whether the provided class name is a proxy
*
* @psalm-template RealClassName of object
* @psalm-param class-string|class-string> $className
*/
public function isProxyClassName(string $className): bool;
}
src/ProxyManager/Inflector/Util/ParameterEncoder.php 0000644 00000000772 13721511157 0016553 0 ustar 00
* $interceptor = function ($proxy, $instance, string $method, array $params, & $returnEarly) {};
*
*
* @param string $methodName name of the intercepted method
* @param Closure|null $prefixInterceptor interceptor closure or null to unset the currently active interceptor
*
* @psalm-param null|Closure(
* InterceptedObjectType&AccessInterceptorInterface=,
* InterceptedObjectType=,
* string=,
* array=,
* bool=
* ) : mixed $prefixInterceptor
*/
public function setMethodPrefixInterceptor(string $methodName, ?Closure $prefixInterceptor = null): void;
/**
* Set or remove the suffix interceptor for a method
*
* @link https://github.com/Ocramius/ProxyManager/blob/master/docs/access-interceptor-value-holder.md
*
* A prefix interceptor should have a signature like following:
*
*
* $interceptor = function ($proxy, $instance, string $method, array $params, $returnValue, & $returnEarly) {};
*
*
* @param string $methodName name of the intercepted method
* @param Closure|null $suffixInterceptor interceptor closure or null to unset the currently active interceptor
*
* @psalm-param null|Closure(
* InterceptedObjectType&AccessInterceptorInterface=,
* InterceptedObjectType=,
* string=,
* array=,
* mixed=,
* bool=
* ) : mixed $suffixInterceptor
*/
public function setMethodSuffixInterceptor(string $methodName, ?Closure $suffixInterceptor = null): void;
}
src/ProxyManager/Proxy/AccessInterceptorValueHolderInterface.php 0000644 00000003340 13721511157 0021200 0 ustar 00 =,
* bool=
* ) : mixed $prefixInterceptor
*/
public function setMethodPrefixInterceptor(string $methodName, ?Closure $prefixInterceptor = null): void;
/**
* {@inheritDoc}
*
* Definitions are duplicated here to allow templated definitions in this child type
*
* @param string $methodName name of the intercepted method
* @param Closure|null $suffixInterceptor interceptor closure or null to unset the currently active interceptor
*
* @psalm-param null|Closure(
* InterceptedObjectType&AccessInterceptorInterface=,
* InterceptedObjectType=,
* string=,
* array=,
* mixed=,
* bool=
* ) : mixed $suffixInterceptor
*/
public function setMethodSuffixInterceptor(string $methodName, ?Closure $suffixInterceptor = null): void;
/**
* {@inheritDoc}
*
* Definitions are duplicated here to allow templated definitions in this child type
*
* @psalm-return InterceptedObjectType|null
*/
public function getWrappedValueHolderValue(): ?object;
}
src/ProxyManager/Proxy/Exception/RemoteObjectException.php 0000644 00000000423 13721511157 0020002 0 ustar 00 =,
* string=,
* array=,
* ?Closure=,
* array=
* ) : bool $initializer
*/
public function setProxyInitializer(?Closure $initializer = null);
/**
* {@inheritDoc}
*
* Definitions are duplicated here to allow templated definitions in this child type
*
* @psalm-suppress ImplementedReturnTypeMismatch Note that the closure signature below is slightly different
* from the one declared in LazyLoadingInterface.
* @psalm-return null|Closure(
* LazilyLoadedObjectType&GhostObjectInterface=,
* string,
* array=,
* ?Closure=,
* array=
* ) : bool
*/
public function getProxyInitializer(): ?Closure;
}
src/ProxyManager/Proxy/LazyLoadingInterface.php 0000644 00000003467 13721511157 0015654 0 ustar 00
* $initializer = function (
* & ?object $wrappedObject,
* LazyLoadingInterface $proxy,
* string $calledMethod,
* array $callParameters,
* & ?\Closure $initializer,
* array $propertiesToBeSet = [] // works only on ghost objects
* ) {};
*
*
* @return void
*
* @psalm-param null|Closure(
* LazilyLoadedObjectType|null=,
* LazilyLoadedObjectType&LazyLoadingInterface=,
* string=,
* array=,
* ?Closure=,
* array=
* ) : bool $initializer
*/
public function setProxyInitializer(?Closure $initializer = null);
/**
* @psalm-return null|Closure(
* LazilyLoadedObjectType|null=,
* LazilyLoadedObjectType&LazyLoadingInterface=,
* string,
* array=,
* ?Closure=,
* array=
* ) : bool
*/
public function getProxyInitializer(): ?Closure;
/**
* Force initialization of the proxy
*
* @return bool true if the proxy could be initialized
*/
public function initializeProxy(): bool;
/**
* Retrieves current initialization status of the proxy
*/
public function isProxyInitialized(): bool;
}
src/ProxyManager/Proxy/NullObjectInterface.php 0000644 00000000227 13721511157 0015467 0 ustar 00 setBody(UnsetPropertiesGenerator::generateSnippet(
Properties::fromReflectionClass($originalClass),
'this'
));
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptor/MethodGenerator/SetMethodPrefixInterceptor.php 0000644 00000002232 13721511157 0027452 0 ustar 00 setType(Closure::class);
$interceptor->setDefaultValue(null);
$this->setParameter(new ParameterGenerator('methodName', 'string'));
$this->setParameter($interceptor);
$this->setReturnType('void');
$this->setBody('$this->' . $prefixInterceptor->getName() . '[$methodName] = $prefixInterceptor;');
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptor/MethodGenerator/SetMethodSuffixInterceptor.php 0000644 00000002232 13721511157 0027461 0 ustar 00 setType(Closure::class);
$interceptor->setDefaultValue(null);
$this->setParameter(new ParameterGenerator('methodName', 'string'));
$this->setParameter($interceptor);
$this->setReturnType('void');
$this->setBody('$this->' . $suffixInterceptor->getName() . '[$methodName] = $suffixInterceptor;');
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptor/PropertyGenerator/MethodPrefixInterceptors.php 0000644 00000001532 13721511157 0027567 0 ustar 00 setDefaultValue([]);
$this->setVisibility(self::VISIBILITY_PRIVATE);
$this->setDocBlock('@var \\Closure[] map of interceptors to be called per-method before execution');
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptor/PropertyGenerator/MethodSuffixInterceptors.php 0000644 00000001530 13721511157 0027574 0 ustar 00 setDefaultValue([]);
$this->setVisibility(self::VISIBILITY_PRIVATE);
$this->setDocBlock('@var \\Closure[] map of interceptors to be called per-method after execution');
}
}
ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/BindProxyProperties.php 0000644 00000006003 13721511157 0030734 0 ustar 00 src getName()),
new ParameterGenerator('prefixInterceptors', 'array', []),
new ParameterGenerator('suffixInterceptors', 'array', []),
],
self::FLAG_PRIVATE,
null,
"@override constructor to setup interceptors\n\n"
. '@param \\' . $originalClass->getName() . " \$localizedObject\n"
. "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n"
. '@param \\Closure[] $suffixInterceptors method interceptors to be used before method logic'
);
$localizedProperties = [];
$properties = Properties::fromReflectionClass($originalClass);
$nonReferenceableProperties = $properties
->onlyNonReferenceableProperties()
->onlyInstanceProperties();
if (! $nonReferenceableProperties->empty()) {
throw UnsupportedProxiedClassException::nonReferenceableLocalizedReflectionProperties(
$originalClass,
$nonReferenceableProperties
);
}
foreach ($properties->getAccessibleProperties() as $property) {
$propertyName = $property->getName();
$localizedProperties[] = '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ';';
}
foreach ($properties->getPrivateProperties() as $property) {
$propertyName = $property->getName();
$localizedProperties[] = "\\Closure::bind(function () use (\$localizedObject) {\n "
. '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ";\n"
. '}, $this, ' . var_export($property->getDeclaringClass()->getName(), true)
. ')->__invoke();';
}
$this->setBody(
($localizedProperties ? implode("\n\n", $localizedProperties) . "\n\n" : '')
. '$this->' . $prefixInterceptors->getName() . " = \$prefixInterceptors;\n"
. '$this->' . $suffixInterceptors->getName() . ' = $suffixInterceptors;'
);
}
}
ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/InterceptedMethod.php 0000644 00000002727 13721511157 0030361 0 ustar 00 src getParameters() as $parameter) {
$forwardedParams[] = ($parameter->isVariadic() ? '...' : '') . '$' . $parameter->getName();
}
$method->setBody(InterceptorGenerator::createInterceptedMethodBody(
'$returnValue = parent::'
. $originalMethod->getName() . '(' . implode(', ', $forwardedParams) . ');',
$method,
$prefixInterceptors,
$suffixInterceptors,
$originalMethod
));
return $method;
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicClone.php 0000644 00000002146 13721511157 0027025 0 ustar 00 setBody(InterceptorGenerator::createInterceptedMethodBody(
$parent ? '$returnValue = parent::__clone();' : '$returnValue = null;',
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicGet.php 0000644 00000003074 13721511157 0026505 0 ustar 00 setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicIsset.php 0000644 00000003117 13721511157 0027053 0 ustar 00 setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicSet.php 0000644 00000003226 13721511157 0026520 0 ustar 00 setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicSleep.php 0000644 00000002241 13721511157 0027031 0 ustar 00 setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/MagicUnset.php 0000644 00000003117 13721511157 0027062 0 ustar 00 setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}
ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/StaticProxyConstructor.php 0000644 00000004133 13721511157 0031502 0 ustar 00 src/ProxyManager setType($originalClass->getName());
$prefix->setDefaultValue([]);
$suffix->setDefaultValue([]);
$prefix->setType('array');
$suffix->setType('array');
$this->setParameter($localizedObject);
$this->setParameter($prefix);
$this->setParameter($suffix);
$this->setReturnType($originalClass->getName());
$this->setDocBlock(
"Constructor to setup interceptors\n\n"
. '@param \\' . $originalClass->getName() . " \$localizedObject\n"
. "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n"
. "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic\n\n"
. '@return self'
);
$this->setBody(
'static $reflection;' . "\n\n"
. '$reflection = $reflection ?? new \ReflectionClass(__CLASS__);' . "\n"
. '$instance = $reflection->newInstanceWithoutConstructor();' . "\n\n"
. '$instance->bindProxyProperties($localizedObject, $prefixInterceptors, $suffixInterceptors);' . "\n\n"
. 'return $instance;'
);
}
}
ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Util/InterceptorGenerator.php 0000644 00000006032 13721511157 0032025 0 ustar 00 src/ProxyManager {{$prefixInterceptorsName}}[{{$name}}])) {
$returnEarly = false;
$prefixReturnValue = $this->{{$prefixInterceptorsName}}[{{$name}}]->__invoke($this, $this, {{$name}}, {{$paramsString}}, $returnEarly);
if ($returnEarly) {
{{$prefixEarlyReturnExpression}}
}
}
{{$methodBody}}
if (isset($this->{{$suffixInterceptorsName}}[{{$name}}])) {
$returnEarly = false;
$suffixReturnValue = $this->{{$suffixInterceptorsName}}[{{$name}}]->__invoke($this, $this, {{$name}}, {{$paramsString}}, $returnValue, $returnEarly);
if ($returnEarly) {
{{$suffixEarlyReturnExpression}}
}
}
{{$returnExpression}}
PHP;
/**
* @param string $methodBody the body of the previously generated code.
* It MUST assign the return value to a variable
* `$returnValue` instead of directly returning
*/
public static function createInterceptedMethodBody(
string $methodBody,
MethodGenerator $method,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors,
?ReflectionMethod $originalMethod
): string {
$replacements = [
'{{$name}}' => var_export($method->getName(), true),
'{{$prefixInterceptorsName}}' => $prefixInterceptors->getName(),
'{{$prefixEarlyReturnExpression}}' => ProxiedMethodReturnExpression::generate('$prefixReturnValue', $originalMethod),
'{{$methodBody}}' => $methodBody,
'{{$suffixInterceptorsName}}' => $suffixInterceptors->getName(),
'{{$suffixEarlyReturnExpression}}' => ProxiedMethodReturnExpression::generate('$suffixReturnValue', $originalMethod),
'{{$returnExpression}}' => ProxiedMethodReturnExpression::generate('$returnValue', $originalMethod),
'{{$paramsString}}' => 'array(' . implode(', ', array_map(static function (ParameterGenerator $parameter): string {
return var_export($parameter->getName(), true) . ' => $' . $parameter->getName();
}, $method->getParameters())) . ')',
];
return str_replace(
array_keys($replacements),
$replacements,
self::TEMPLATE
);
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizerGenerator.php 0000644 00000011473 13721511157 0023607 0 ustar 00 setExtendedClass($originalClass->getName());
$classGenerator->setImplementedInterfaces([AccessInterceptorInterface::class]);
$classGenerator->addPropertyFromGenerator($prefixInterceptors = new MethodPrefixInterceptors());
$classGenerator->addPropertyFromGenerator($suffixInterceptors = new MethodSuffixInterceptors());
array_map(
static function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator): void {
ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
},
array_merge(
array_map(
$this->buildMethodInterceptor($prefixInterceptors, $suffixInterceptors),
ProxiedMethodsFilter::getProxiedMethods(
$originalClass,
['__get', '__set', '__isset', '__unset', '__clone', '__sleep']
)
),
[
new StaticProxyConstructor($originalClass),
new BindProxyProperties($originalClass, $prefixInterceptors, $suffixInterceptors),
new SetMethodPrefixInterceptor($prefixInterceptors),
new SetMethodSuffixInterceptor($suffixInterceptors),
new MagicGet($originalClass, $prefixInterceptors, $suffixInterceptors),
new MagicSet($originalClass, $prefixInterceptors, $suffixInterceptors),
new MagicIsset($originalClass, $prefixInterceptors, $suffixInterceptors),
new MagicUnset($originalClass, $prefixInterceptors, $suffixInterceptors),
new MagicSleep($originalClass, $prefixInterceptors, $suffixInterceptors),
new MagicClone($originalClass, $prefixInterceptors, $suffixInterceptors),
]
)
);
}
private function buildMethodInterceptor(
MethodPrefixInterceptors $prefixInterceptors,
MethodSuffixInterceptors $suffixInterceptors
): callable {
return static function (ReflectionMethod $method) use ($prefixInterceptors, $suffixInterceptors): InterceptedMethod {
return InterceptedMethod::generateMethod(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()),
$prefixInterceptors,
$suffixInterceptors
);
};
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/InterceptedMethod.php 0000644 00000003113 13721511157 0027722 0 ustar 00 getParameters() as $parameter) {
$forwardedParams[] = ($parameter->isVariadic() ? '...' : '') . '$' . $parameter->getName();
}
$method->setBody(InterceptorGenerator::createInterceptedMethodBody(
'$returnValue = $this->' . $valueHolderProperty->getName() . '->'
. $originalMethod->getName() . '(' . implode(', ', $forwardedParams) . ');',
$method,
$valueHolderProperty,
$prefixInterceptors,
$suffixInterceptors,
$originalMethod
));
return $method;
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicClone.php 0000644 00000002717 13721511157 0026325 0 ustar 00 {{$valueHolder}} = clone $this->{{$valueHolder}};
foreach ($this->{{$prefix}} as $key => $value) {
$this->{{$prefix}}[$key] = clone $value;
}
foreach ($this->{{$suffix}} as $key => $value) {
$this->{{$suffix}}[$key] = clone $value;
}
PHP;
/**
* Constructor
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $valueHolderProperty,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
parent::__construct($originalClass, '__clone');
$valueHolder = $valueHolderProperty->getName();
$prefix = $prefixInterceptors->getName();
$suffix = $suffixInterceptors->getName();
$replacements = [
'{{$valueHolder}}' => $valueHolder,
'{{$prefix}}' => $prefix,
'{{$suffix}}' => $suffix,
];
$this->setBody(str_replace(
array_keys($replacements),
$replacements,
self::TEMPLATE
));
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicGet.php 0000644 00000004007 13721511157 0025776 0 ustar 00 getName();
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_GET,
'name',
'value',
$valueHolder,
'returnValue'
);
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' $returnValue = & $this->' . $valueHolderName . '->$name;'
. "\n} else {\n " . $callParent . "\n}\n\n";
}
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicIsset.php 0000644 00000004026 13721511157 0026347 0 ustar 00 getName();
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_ISSET,
'name',
'value',
$valueHolder,
'returnValue'
);
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' $returnValue = isset($this->' . $valueHolderName . '->$name);'
. "\n} else {\n " . $callParent . "\n}\n\n";
}
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicSet.php 0000644 00000004137 13721511157 0026016 0 ustar 00 getName();
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_SET,
'name',
'value',
$valueHolder,
'returnValue'
);
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' $returnValue = ($this->' . $valueHolderName . '->$name = $value);'
. "\n} else {\n " . $callParent . "\n}\n\n";
}
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/MagicUnset.php 0000644 00000004070 13721511157 0026355 0 ustar 00 getName();
$callParent = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_UNSET,
'name',
'value',
$valueHolder,
'returnValue'
);
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' unset($this->' . $valueHolderName . '->$name);'
. "\n} else {\n " . $callParent . "\n}\n\n";
}
$callParent .= '$returnValue = false;';
$this->setBody(InterceptorGenerator::createInterceptedMethodBody(
$callParent,
$this,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$parent
));
}
}
ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/StaticProxyConstructor.php 0000644 00000005005 13721511157 0030775 0 ustar 00 src setDefaultValue([]);
$suffix->setDefaultValue([]);
$prefix->setType('array');
$suffix->setType('array');
$this->setParameter(new ParameterGenerator('wrappedObject'));
$this->setParameter($prefix);
$this->setParameter($suffix);
$this->setReturnType($originalClass->getName());
$this->setDocBlock(
"Constructor to setup interceptors\n\n"
. '@param \\' . $originalClass->getName() . " \$wrappedObject\n"
. "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n"
. "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic\n\n"
. '@return self'
);
$this->setBody(
'static $reflection;' . "\n\n"
. '$reflection = $reflection ?? new \ReflectionClass(__CLASS__);' . "\n"
. '$instance = $reflection->newInstanceWithoutConstructor();' . "\n\n"
. UnsetPropertiesGenerator::generateSnippet(Properties::fromReflectionClass($originalClass), 'instance')
. '$instance->' . $valueHolder->getName() . " = \$wrappedObject;\n"
. '$instance->' . $prefixInterceptors->getName() . " = \$prefixInterceptors;\n"
. '$instance->' . $suffixInterceptors->getName() . " = \$suffixInterceptors;\n\n"
. 'return $instance;'
);
}
}
ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/Util/InterceptorGenerator.php 0000644 00000006440 13721511157 0031324 0 ustar 00 src/ProxyManager {{$prefixInterceptorsName}}[{{$name}}])) {
$returnEarly = false;
$prefixReturnValue = $this->{{$prefixInterceptorsName}}[{{$name}}]->__invoke($this, $this->{{$valueHolderName}}, {{$name}}, {{$paramsString}}, $returnEarly);
if ($returnEarly) {
{{$returnEarlyPrefixExpression}}
}
}
{{$methodBody}}
if (isset($this->{{$suffixInterceptorsName}}[{{$name}}])) {
$returnEarly = false;
$suffixReturnValue = $this->{{$suffixInterceptorsName}}[{{$name}}]->__invoke($this, $this->{{$valueHolderName}}, {{$name}}, {{$paramsString}}, $returnValue, $returnEarly);
if ($returnEarly) {
{{$returnEarlySuffixExpression}}
}
}
{{$returnExpression}}
PHP;
/**
* @param string $methodBody the body of the previously generated code.
* It MUST assign the return value to a variable
* `$returnValue` instead of directly returning
*/
public static function createInterceptedMethodBody(
string $methodBody,
MethodGenerator $method,
PropertyGenerator $valueHolder,
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors,
?ReflectionMethod $originalMethod
): string {
$name = var_export($method->getName(), true);
$valueHolderName = $valueHolder->getName();
$prefixInterceptorsName = $prefixInterceptors->getName();
$suffixInterceptorsName = $suffixInterceptors->getName();
$params = [];
foreach ($method->getParameters() as $parameter) {
$parameterName = $parameter->getName();
$params[] = var_export($parameterName, true) . ' => $' . $parameter->getName();
}
$paramsString = 'array(' . implode(', ', $params) . ')';
$replacements = [
'{{$prefixInterceptorsName}}' => $prefixInterceptorsName,
'{{$name}}' => $name,
'{{$valueHolderName}}' => $valueHolderName,
'{{$paramsString}}' => $paramsString,
'{{$returnEarlyPrefixExpression}}' => ProxiedMethodReturnExpression::generate('$prefixReturnValue', $originalMethod),
'{{$methodBody}}' => $methodBody,
'{{$suffixInterceptorsName}}' => $suffixInterceptorsName,
'{{$returnEarlySuffixExpression}}' => ProxiedMethodReturnExpression::generate('$suffixReturnValue', $originalMethod),
'{{$returnExpression}}' => ProxiedMethodReturnExpression::generate('$returnValue', $originalMethod),
];
return str_replace(array_keys($replacements), $replacements, self::TEMPLATE);
}
}
src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolderGenerator.php 0000644 00000014460 13721511157 0023102 0 ustar 00 isInterface()) {
$interfaces[] = $originalClass->getName();
} else {
$classGenerator->setExtendedClass($originalClass->getName());
}
$classGenerator->setImplementedInterfaces($interfaces);
$classGenerator->addPropertyFromGenerator($valueHolder = new ValueHolderProperty($originalClass));
$classGenerator->addPropertyFromGenerator($prefixInterceptors = new MethodPrefixInterceptors());
$classGenerator->addPropertyFromGenerator($suffixInterceptors = new MethodSuffixInterceptors());
$classGenerator->addPropertyFromGenerator($publicProperties);
array_map(
static function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator): void {
ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
},
array_merge(
array_map(
$this->buildMethodInterceptor($prefixInterceptors, $suffixInterceptors, $valueHolder),
ProxiedMethodsFilter::getProxiedMethods($originalClass)
),
[
Constructor::generateMethod($originalClass, $valueHolder),
new StaticProxyConstructor($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors),
new GetWrappedValueHolderValue($valueHolder),
new SetMethodPrefixInterceptor($prefixInterceptors),
new SetMethodSuffixInterceptor($suffixInterceptors),
new MagicGet(
$originalClass,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$publicProperties
),
new MagicSet(
$originalClass,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$publicProperties
),
new MagicIsset(
$originalClass,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$publicProperties
),
new MagicUnset(
$originalClass,
$valueHolder,
$prefixInterceptors,
$suffixInterceptors,
$publicProperties
),
new MagicClone($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors),
new MagicSleep($originalClass, $valueHolder),
new MagicWakeup($originalClass),
]
)
);
}
private function buildMethodInterceptor(
MethodPrefixInterceptors $prefixes,
MethodSuffixInterceptors $suffixes,
ValueHolderProperty $valueHolder
): callable {
return static function (ReflectionMethod $method) use ($prefixes, $suffixes, $valueHolder): InterceptedMethod {
return InterceptedMethod::generateMethod(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()),
$valueHolder,
$prefixes,
$suffixes
);
};
}
}
src/ProxyManager/ProxyGenerator/Assertion/CanProxyAssertion.php 0000644 00000004113 13721511157 0021054 0 ustar 00 isFinal()) {
throw InvalidProxiedClassException::finalClassNotSupported($originalClass);
}
}
/**
* @throws InvalidProxiedClassException
*/
private static function hasNoAbstractProtectedMethods(ReflectionClass $originalClass): void
{
$protectedAbstract = array_filter(
$originalClass->getMethods(),
static function (ReflectionMethod $method): bool {
return $method->isAbstract() && $method->isProtected();
}
);
if ($protectedAbstract) {
throw InvalidProxiedClassException::abstractProtectedMethodsNotSupported($originalClass);
}
}
/**
* @throws InvalidProxiedClassException
*/
private static function isNotInterface(ReflectionClass $originalClass): void
{
if ($originalClass->isInterface()) {
throw InvalidProxiedClassException::interfaceNotSupported($originalClass);
}
}
}
src/ProxyManager/ProxyGenerator/LazyLoading/MethodGenerator/StaticProxyConstructor.php 0000644 00000002705 13721511157 0025522 0 ustar 00 setParameter(new ParameterGenerator('initializer'));
$this->setDocBlock("Constructor for lazy initialization\n\n@param \\Closure|null \$initializer");
$this->setBody(
'static $reflection;' . "\n\n"
. '$reflection = $reflection ?? new \ReflectionClass(__CLASS__);' . "\n"
. '$instance = $reflection->newInstanceWithoutConstructor();' . "\n\n"
. UnsetPropertiesGenerator::generateSnippet($properties, 'instance')
. '$instance->' . $initializerProperty->getName() . ' = $initializer;' . "\n\n"
. 'return $instance;'
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/CallInitializer.php 0000644 00000013126 13721511157 0025046 0 ustar 00 getName();
$initialization = $initTracker->getName();
$bodyTemplate = <<<'PHP'
if ($this->%s || ! $this->%s) {
return;
}
$this->%s = true;
%s
%s
$result = $this->%s->__invoke($this, $methodName, $parameters, $this->%s, $properties);
$this->%s = false;
return $result;
PHP;
$referenceableProperties = $properties->withoutNonReferenceableProperties();
$this->setBody(sprintf(
$bodyTemplate,
$initialization,
$initializer,
$initialization,
$this->propertiesInitializationCode($referenceableProperties),
$this->propertiesReferenceArrayCode($referenceableProperties),
$initializer,
$initializer,
$initialization
));
}
private function propertiesInitializationCode(Properties $properties): string
{
$assignments = [];
foreach ($properties->getAccessibleProperties() as $property) {
$assignments[] = '$this->'
. $property->getName()
. ' = ' . $this->getExportedPropertyDefaultValue($property)
. ';';
}
foreach ($properties->getGroupedPrivateProperties() as $className => $privateProperties) {
$cacheKey = 'cache' . str_replace('\\', '_', $className);
$assignments[] = 'static $' . $cacheKey . ";\n\n"
. '$' . $cacheKey . ' ?: $' . $cacheKey . " = \\Closure::bind(static function (\$instance) {\n"
. $this->getPropertyDefaultsAssignments($privateProperties) . "\n"
. '}, null, ' . var_export($className, true) . ");\n\n"
. '$' . $cacheKey . "(\$this);\n\n";
}
return implode("\n", $assignments) . "\n\n";
}
/**
* @param ReflectionProperty[] $properties
*/
private function getPropertyDefaultsAssignments(array $properties): string
{
return implode(
"\n",
array_map(
function (ReflectionProperty $property): string {
return ' $instance->' . $property->getName()
. ' = ' . $this->getExportedPropertyDefaultValue($property) . ';';
},
$properties
)
);
}
private function propertiesReferenceArrayCode(Properties $properties): string
{
$assignments = [];
foreach ($properties->getAccessibleProperties() as $propertyInternalName => $property) {
$assignments[] = ' '
. var_export($propertyInternalName, true) . ' => & $this->' . $property->getName()
. ',';
}
$code = "\$properties = [\n" . implode("\n", $assignments) . "\n];\n\n";
// must use assignments, as direct reference during array definition causes a fatal error (not sure why)
foreach ($properties->getGroupedPrivateProperties() as $className => $classPrivateProperties) {
$cacheKey = 'cacheFetch' . str_replace('\\', '_', $className);
$code .= 'static $' . $cacheKey . ";\n\n"
. '$' . $cacheKey . ' ?: $' . $cacheKey
. " = \\Closure::bind(function (\$instance, array & \$properties) {\n"
. $this->generatePrivatePropertiesAssignmentsCode($classPrivateProperties)
. '}, $this, ' . var_export($className, true) . ");\n\n"
. '$' . $cacheKey . '($this, $properties);';
}
return $code;
}
/**
* @param array $properties indexed by internal name
*/
private function generatePrivatePropertiesAssignmentsCode(array $properties): string
{
$code = '';
foreach ($properties as $property) {
$key = "\0" . $property->getDeclaringClass()->getName() . "\0" . $property->getName();
$code .= ' $properties[' . var_export($key, true) . '] = '
. '& $instance->' . $property->getName() . ";\n";
}
return $code;
}
private function getExportedPropertyDefaultValue(ReflectionProperty $property): string
{
$name = $property->getName();
$defaults = $property->getDeclaringClass()->getDefaultProperties();
return var_export($defaults[$name] ?? null, true);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/GetProxyInitializer.php 0000644 00000001436 13721511157 0025755 0 ustar 00 setReturnType('?\\Closure');
$this->setBody('return $this->' . $initializerProperty->getName() . ';');
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/InitializeProxy.php 0000644 00000001730 13721511157 0025130 0 ustar 00 setReturnType('bool');
$this->setBody(
'return $this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'initializeProxy\', []);'
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/IsProxyInitialized.php 0000644 00000001427 13721511157 0025573 0 ustar 00 setReturnType('bool');
$this->setBody('return ! $this->' . $initializerProperty->getName() . ';');
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicClone.php 0000644 00000001604 13721511157 0023766 0 ustar 00 setBody(
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__clone\', []);'
. ($originalClass->hasMethod('__clone') ? "\n\nparent::__clone();" : '')
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php 0000644 00000010367 13721511157 0023453 0 ustar 00 %s && ! $this->%s && $this->%s('__get', array('name' => $name));
if (isset(self::$%s[$name])) {
return $this->$name;
}
if (isset(self::$%s[$name])) {
if ($this->%s) {
return $this->$name;
}
// check protected property access via compatible class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$object = isset($caller['object']) ? $caller['object'] : '';
$expectedType = self::$%s[$name];
if ($object instanceof $expectedType) {
return $this->$name;
}
$class = isset($caller['class']) ? $caller['class'] : '';
if ($class === $expectedType || is_subclass_of($class, $expectedType) || $class === 'ReflectionProperty') {
return $this->$name;
}
} elseif (isset(self::$%s[$name])) {
// check private property access via same class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$class = isset($caller['class']) ? $caller['class'] : '';
static $accessorCache = [];
if (isset(self::$%s[$name][$class])) {
$cacheKey = $class . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(static function & ($instance) use ($name) {
return $instance->$name;
}, null, $class);
return $accessor($this);
}
if ($this->%s || 'ReflectionProperty' === $class) {
$tmpClass = key(self::$%s[$name]);
$cacheKey = $tmpClass . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(static function & ($instance) use ($name) {
return $instance->$name;
}, null, $tmpClass);
return $accessor($this);
}
}
%s
PHP;
/**
* @throws InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $initializerProperty,
MethodGenerator $callInitializer,
PublicPropertiesMap $publicProperties,
ProtectedPropertiesMap $protectedProperties,
PrivatePropertiesMap $privateProperties,
InitializationTracker $initializationTracker
) {
parent::__construct($originalClass, '__get', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__get');
$parentAccess = 'return parent::__get($name);';
if (! $override) {
$parentAccess = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_GET,
'name'
);
}
$this->setBody(sprintf(
$this->callParentTemplate,
$initializerProperty->getName(),
$initializationTracker->getName(),
$callInitializer->getName(),
$publicProperties->getName(),
$protectedProperties->getName(),
$initializationTracker->getName(),
$protectedProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$initializationTracker->getName(),
$privateProperties->getName(),
$parentAccess
));
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicIsset.php 0000644 00000007540 13721511157 0024022 0 ustar 00 $name);
}
if (isset(self::$%s[$name])) {
// check protected property access via compatible class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$object = isset($caller['object']) ? $caller['object'] : '';
$expectedType = self::$%s[$name];
if ($object instanceof $expectedType) {
return isset($this->$name);
}
$class = isset($caller['class']) ? $caller['class'] : '';
if ($class === $expectedType || is_subclass_of($class, $expectedType)) {
return isset($this->$name);
}
} else {
// check private property access via same class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$class = isset($caller['class']) ? $caller['class'] : '';
static $accessorCache = [];
if (isset(self::$%s[$name][$class])) {
$cacheKey = $class . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(static function ($instance) use ($name) {
return isset($instance->$name);
}, null, $class);
return $accessor($this);
}
if ('ReflectionProperty' === $class) {
$tmpClass = key(self::$%s[$name]);
$cacheKey = $tmpClass . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(static function ($instance) use ($name) {
return isset($instance->$name);
}, null, $tmpClass);
return $accessor($this);
}
}
%s
PHP;
/**
* @throws InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $initializerProperty,
MethodGenerator $callInitializer,
PublicPropertiesMap $publicProperties,
ProtectedPropertiesMap $protectedProperties,
PrivatePropertiesMap $privateProperties
) {
parent::__construct($originalClass, '__isset', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__isset');
$parentAccess = 'return parent::__isset($name);';
if (! $override) {
$parentAccess = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_ISSET,
'name'
);
}
$this->setBody(sprintf(
$this->callParentTemplate,
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__isset\', array(\'name\' => $name));',
$publicProperties->getName(),
$protectedProperties->getName(),
$protectedProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$parentAccess
));
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicSet.php 0000644 00000010156 13721511157 0023463 0 ustar 00 $name = $value);
}
if (isset(self::$%s[$name])) {
// check protected property access via compatible class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$object = isset($caller['object']) ? $caller['object'] : '';
$expectedType = self::$%s[$name];
if ($object instanceof $expectedType) {
return ($this->$name = $value);
}
$class = isset($caller['class']) ? $caller['class'] : '';
if ($class === $expectedType || is_subclass_of($class, $expectedType) || $class === 'ReflectionProperty') {
return ($this->$name = $value);
}
} elseif (isset(self::$%s[$name])) {
// check private property access via same class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$class = isset($caller['class']) ? $caller['class'] : '';
static $accessorCache = [];
if (isset(self::$%s[$name][$class])) {
$cacheKey = $class . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(static function ($instance, $value) use ($name) {
return ($instance->$name = $value);
}, null, $class);
return $accessor($this, $value);
}
if ('ReflectionProperty' === $class) {
$tmpClass = key(self::$%s[$name]);
$cacheKey = $tmpClass . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(static function ($instance, $value) use ($name) {
return ($instance->$name = $value);
}, null, $tmpClass);
return $accessor($this, $value);
}
}
%s
PHP;
/**
* @throws InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $initializerProperty,
MethodGenerator $callInitializer,
PublicPropertiesMap $publicProperties,
ProtectedPropertiesMap $protectedProperties,
PrivatePropertiesMap $privateProperties
) {
parent::__construct(
$originalClass,
'__set',
[new ParameterGenerator('name'), new ParameterGenerator('value')]
);
$override = $originalClass->hasMethod('__set');
$parentAccess = 'return parent::__set($name, $value);';
if (! $override) {
$parentAccess = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_SET,
'name',
'value'
);
}
$this->setBody(sprintf(
$this->callParentTemplate,
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__set\', array(\'name\' => $name, \'value\' => $value));',
$publicProperties->getName(),
$protectedProperties->getName(),
$protectedProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$parentAccess
));
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicSleep.php 0000644 00000001661 13721511157 0024001 0 ustar 00 setBody(
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__sleep\', []);' . "\n\n"
. ($originalClass->hasMethod('__sleep') ? 'return parent::__sleep();' : 'return array_keys((array) $this);')
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicUnset.php 0000644 00000007726 13721511157 0024037 0 ustar 00 $name);
return;
}
if (isset(self::$%s[$name])) {
// check protected property access via compatible class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$object = isset($caller['object']) ? $caller['object'] : '';
$expectedType = self::$%s[$name];
if ($object instanceof $expectedType) {
unset($this->$name);
return;
}
$class = isset($caller['class']) ? $caller['class'] : '';
if ($class === $expectedType || is_subclass_of($class, $expectedType) || $class === 'ReflectionProperty') {
unset($this->$name);
return;
}
} elseif (isset(self::$%s[$name])) {
// check private property access via same class
$callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$caller = isset($callers[1]) ? $callers[1] : [];
$class = isset($caller['class']) ? $caller['class'] : '';
static $accessorCache = [];
if (isset(self::$%s[$name][$class])) {
$cacheKey = $class . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(static function ($instance) use ($name) {
unset($instance->$name);
}, null, $class);
return $accessor($this);
}
if ('ReflectionProperty' === $class) {
$tmpClass = key(self::$%s[$name]);
$cacheKey = $tmpClass . '#' . $name;
$accessor = isset($accessorCache[$cacheKey])
? $accessorCache[$cacheKey]
: $accessorCache[$cacheKey] = \Closure::bind(static function ($instance) use ($name) {
unset($instance->$name);
}, null, $tmpClass);
return $accessor($this);
}
}
%s
PHP;
/**
* @throws InvalidArgumentException
*/
public function __construct(
ReflectionClass $originalClass,
PropertyGenerator $initializerProperty,
MethodGenerator $callInitializer,
PublicPropertiesMap $publicProperties,
ProtectedPropertiesMap $protectedProperties,
PrivatePropertiesMap $privateProperties
) {
parent::__construct($originalClass, '__unset', [new ParameterGenerator('name')]);
$override = $originalClass->hasMethod('__unset');
$parentAccess = 'return parent::__unset($name);';
if (! $override) {
$parentAccess = PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_UNSET,
'name'
);
}
$this->setBody(sprintf(
$this->callParentTemplate,
'$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName()
. '(\'__unset\', array(\'name\' => $name));',
$publicProperties->getName(),
$protectedProperties->getName(),
$protectedProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$privateProperties->getName(),
$parentAccess
));
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/SetProxyInitializer.php 0000644 00000001544 13721511157 0025771 0 ustar 00 setDefaultValue(null)],
self::FLAG_PUBLIC,
'$this->' . $initializerProperty->getName() . ' = $initializer;'
);
$this->setReturnType('void');
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/InitializationTracker.php 0000644 00000001463 13721511157 0026677 0 ustar 00 setVisibility(self::VISIBILITY_PRIVATE);
$this->setDocBlock('@var bool tracks initialization status - true while the object is initializing');
$this->setDefaultValue(false);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/InitializerProperty.php 0000644 00000001377 13721511157 0026430 0 ustar 00 setVisibility(self::VISIBILITY_PRIVATE);
$this->setDocBlock('@var \\Closure|null initializer responsible for generating the wrapped object');
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/PrivatePropertiesMap.php 0000644 00000002613 13721511157 0026517 0 ustar 00 setVisibility(self::VISIBILITY_PRIVATE);
$this->setStatic(true);
$this->setDocBlock(
'@var array[][] visibility and default value of defined properties, indexed by property name and class name'
);
$this->setDefaultValue($this->getMap($properties));
}
/**
* @return array>
*/
private function getMap(Properties $properties): array
{
$map = [];
foreach ($properties->getPrivateProperties() as $property) {
$map[$property->getName()][$property->getDeclaringClass()->getName()] = true;
}
return $map;
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhost/PropertyGenerator/ProtectedPropertiesMap.php 0000644 00000002556 13721511157 0027044 0 ustar 00 setVisibility(self::VISIBILITY_PRIVATE);
$this->setStatic(true);
$this->setDocBlock(
'@var string[][] declaring class name of defined protected properties, indexed by property name'
);
$this->setDefaultValue($this->getMap($properties));
}
/** @return string[] */
private function getMap(Properties $properties): array
{
$map = [];
foreach ($properties->getProtectedProperties() as $property) {
$map[$property->getName()] = $property->getDeclaringClass()->getName();
}
return $map;
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingGhostGenerator.php 0000644 00000015020 13721511157 0020542 0 ustar 00 } $proxyOptions
*/
public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator, array $proxyOptions = [])
{
CanProxyAssertion::assertClassCanBeProxied($originalClass, false);
$filteredProperties = Properties::fromReflectionClass($originalClass)
->filter($proxyOptions['skippedProperties'] ?? []);
$publicProperties = new PublicPropertiesMap($filteredProperties);
$privateProperties = new PrivatePropertiesMap($filteredProperties);
$protectedProperties = new ProtectedPropertiesMap($filteredProperties);
$classGenerator->setExtendedClass($originalClass->getName());
$classGenerator->setImplementedInterfaces([GhostObjectInterface::class]);
$classGenerator->addPropertyFromGenerator($initializer = new InitializerProperty());
$classGenerator->addPropertyFromGenerator($initializationTracker = new InitializationTracker());
$classGenerator->addPropertyFromGenerator($publicProperties);
$classGenerator->addPropertyFromGenerator($privateProperties);
$classGenerator->addPropertyFromGenerator($protectedProperties);
$init = new CallInitializer($initializer, $initializationTracker, $filteredProperties);
array_map(
static function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator): void {
ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
},
array_merge(
$this->getAbstractProxiedMethods($originalClass),
[
$init,
new StaticProxyConstructor($initializer, $filteredProperties),
new MagicGet(
$originalClass,
$initializer,
$init,
$publicProperties,
$protectedProperties,
$privateProperties,
$initializationTracker
),
new MagicSet(
$originalClass,
$initializer,
$init,
$publicProperties,
$protectedProperties,
$privateProperties
),
new MagicIsset(
$originalClass,
$initializer,
$init,
$publicProperties,
$protectedProperties,
$privateProperties
),
new MagicUnset(
$originalClass,
$initializer,
$init,
$publicProperties,
$protectedProperties,
$privateProperties
),
new MagicClone($originalClass, $initializer, $init),
new MagicSleep($originalClass, $initializer, $init),
new SetProxyInitializer($initializer),
new GetProxyInitializer($initializer),
new InitializeProxy($initializer, $init),
new IsProxyInitialized($initializer),
]
)
);
}
/**
* Retrieves all abstract methods to be proxied
*
* @return MethodGenerator[]
*/
private function getAbstractProxiedMethods(ReflectionClass $originalClass): array
{
return array_map(
static function (ReflectionMethod $method): ProxyManagerMethodGenerator {
$generated = ProxyManagerMethodGenerator::fromReflectionWithoutBodyAndDocBlock(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName())
);
$generated->setAbstract(false);
return $generated;
},
ProxiedMethodsFilter::getAbstractProxiedMethods($originalClass)
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/GetProxyInitializer.php 0000644 00000001444 13721511157 0027102 0 ustar 00 setReturnType('?\\Closure');
$this->setBody('return $this->' . $initializerProperty->getName() . ';');
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/InitializeProxy.php 0000644 00000002052 13721511157 0026254 0 ustar 00 setReturnType('bool');
$initializer = $initializerProperty->getName();
$this->setBody(
'return $this->' . $initializer . ' && $this->' . $initializer
. '->__invoke($this->' . $valueHolderProperty->getName()
. ', $this, \'initializeProxy\', array(), $this->' . $initializer . ');'
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/IsProxyInitialized.php 0000644 00000001444 13721511157 0026720 0 ustar 00 setReturnType('bool');
$this->setBody('return null !== $this->' . $valueHolderProperty->getName() . ';');
}
}
ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/LazyLoadingMethodInterceptor.php 0000644 00000004135 13721511157 0030633 0 ustar 00 src getName();
$valueHolderName = $valueHolderProperty->getName();
$parameters = $originalMethod->getParameters();
$methodName = $originalMethod->getName();
$initializerParams = [];
$forwardedParams = [];
foreach ($parameters as $parameter) {
$parameterName = $parameter->getName();
$variadicPrefix = $parameter->isVariadic() ? '...' : '';
$initializerParams[] = var_export($parameterName, true) . ' => $' . $parameterName;
$forwardedParams[] = $variadicPrefix . '$' . $parameterName;
}
$method->setBody(
'$this->' . $initializerName
. ' && $this->' . $initializerName
. '->__invoke($this->' . $valueHolderName . ', $this, ' . var_export($methodName, true)
. ', array(' . implode(', ', $initializerParams) . '), $this->' . $initializerName . ");\n\n"
. ProxiedMethodReturnExpression::generate(
'$this->' . $valueHolderName . '->' . $methodName . '(' . implode(', ', $forwardedParams) . ')',
$originalMethod
)
);
return $method;
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicClone.php 0000644 00000002033 13721511157 0025111 0 ustar 00 getName();
$valueHolder = $valueHolderProperty->getName();
$this->setBody(
'$this->' . $initializer . ' && $this->' . $initializer
. '->__invoke($this->' . $valueHolder
. ', $this, \'__clone\', array(), $this->' . $initializer . ');' . "\n\n"
. '$this->' . $valueHolder . ' = clone $this->' . $valueHolder . ';'
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicGet.php 0000644 00000004344 13721511157 0024577 0 ustar 00 hasMethod('__get');
$initializer = $initializerProperty->getName();
$valueHolder = $valueHolderProperty->getName();
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' return $this->' . $valueHolder . '->$name;'
. "\n}\n\n";
if ($hasParent) {
$this->setInitializerBody(
$initializer,
$valueHolder,
$callParent . 'return $this->' . $valueHolder . '->__get($name);'
);
return;
}
$this->setInitializerBody(
$initializer,
$valueHolder,
$callParent . PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_GET,
'name',
null,
$valueHolderProperty
)
);
}
private function setInitializerBody(string $initializer, string $valueHolder, string $callParent): void
{
$this->setBody(
'$this->' . $initializer . ' && $this->' . $initializer
. '->__invoke($this->' . $valueHolder . ', $this, \'__get\', [\'name\' => $name], $this->'
. $initializer . ');'
. "\n\n" . $callParent
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicIsset.php 0000644 00000003454 13721511157 0025150 0 ustar 00 getName();
$valueHolder = $valueHolderProperty->getName();
$callParent = '';
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' return isset($this->' . $valueHolder . '->$name);'
. "\n}\n\n";
}
$callParent .= PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_ISSET,
'name',
null,
$valueHolderProperty
);
$this->setBody(
'$this->' . $initializer . ' && $this->' . $initializer
. '->__invoke($this->' . $valueHolder . ', $this, \'__isset\', array(\'name\' => $name), $this->'
. $initializer . ');' . "\n\n" . $callParent
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicSet.php 0000644 00000004111 13721511157 0024603 0 ustar 00 hasMethod('__set');
$initializer = $initializerProperty->getName();
$valueHolder = $valueHolderProperty->getName();
$callParent = '';
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' return ($this->' . $valueHolder . '->$name = $value);'
. "\n}\n\n";
}
$callParent .= $hasParent
? 'return $this->' . $valueHolder . '->__set($name, $value);'
: PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_SET,
'name',
'value',
$valueHolderProperty
);
$this->setBody(
'$this->' . $initializer . ' && $this->' . $initializer
. '->__invoke($this->' . $valueHolder . ', $this, '
. '\'__set\', array(\'name\' => $name, \'value\' => $value), $this->' . $initializer . ');'
. "\n\n" . $callParent
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicSleep.php 0000644 00000002052 13721511157 0025122 0 ustar 00 getName();
$valueHolder = $valueHolderProperty->getName();
$this->setBody(
'$this->' . $initializer . ' && $this->' . $initializer
. '->__invoke($this->' . $valueHolder . ', $this, \'__sleep\', array(), $this->'
. $initializer . ');' . "\n\n"
. 'return array(' . var_export($valueHolder, true) . ');'
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/MagicUnset.php 0000644 00000003747 13721511157 0025164 0 ustar 00 hasMethod('__unset');
$initializer = $initializerProperty->getName();
$valueHolder = $valueHolderProperty->getName();
$callParent = '';
if (! $publicProperties->isEmpty()) {
$callParent = 'if (isset(self::$' . $publicProperties->getName() . "[\$name])) {\n"
. ' unset($this->' . $valueHolder . '->$name);' . "\n\n return;"
. "\n}\n\n";
}
$callParent .= $hasParent
? 'return $this->' . $valueHolder . '->__unset($name);'
: PublicScopeSimulator::getPublicAccessSimulationCode(
PublicScopeSimulator::OPERATION_UNSET,
'name',
null,
$valueHolderProperty
);
$this->setBody(
'$this->' . $initializer . ' && $this->' . $initializer
. '->__invoke($this->' . $valueHolder . ', $this, \'__unset\', array(\'name\' => $name), $this->'
. $initializer . ');' . "\n\n" . $callParent
);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/MethodGenerator/SetProxyInitializer.php 0000644 00000002115 13721511157 0027112 0 ustar 00 setType(Closure::class);
$initializerParameter->setDefaultValue(null);
$this->setParameter($initializerParameter);
$this->setBody('$this->' . $initializerProperty->getName() . ' = $initializer;');
$this->setReturnType('void');
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/PropertyGenerator/InitializerProperty.php 0000644 00000001405 13721511157 0027546 0 ustar 00 setVisibility(self::VISIBILITY_PRIVATE);
$this->setDocBlock('@var \\Closure|null initializer responsible for generating the wrapped object');
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolder/PropertyGenerator/ValueHolderProperty.php 0000644 00000001757 13721511157 0027507 0 ustar 00 setWordWrap(false);
$docBlock->setLongDescription('@var \\' . $type->getName() . '|null wrapped object, if the proxy is initialized');
$this->setDocBlock($docBlock);
$this->setVisibility(self::VISIBILITY_PRIVATE);
}
}
src/ProxyManager/ProxyGenerator/LazyLoadingValueHolderGenerator.php 0000644 00000012752 13721511157 0021701 0 ustar 00 isInterface()) {
$interfaces[] = $originalClass->getName();
} else {
$classGenerator->setExtendedClass($originalClass->getName());
}
$classGenerator->setImplementedInterfaces($interfaces);
$classGenerator->addPropertyFromGenerator($valueHolder = new ValueHolderProperty($originalClass));
$classGenerator->addPropertyFromGenerator($initializer = new InitializerProperty());
$classGenerator->addPropertyFromGenerator($publicProperties);
array_map(
static function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator): void {
ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
},
array_merge(
array_map(
$this->buildLazyLoadingMethodInterceptor($initializer, $valueHolder),
ProxiedMethodsFilter::getProxiedMethods($originalClass)
),
[
new StaticProxyConstructor($initializer, Properties::fromReflectionClass($originalClass)),
Constructor::generateMethod($originalClass, $valueHolder),
new MagicGet($originalClass, $initializer, $valueHolder, $publicProperties),
new MagicSet($originalClass, $initializer, $valueHolder, $publicProperties),
new MagicIsset($originalClass, $initializer, $valueHolder, $publicProperties),
new MagicUnset($originalClass, $initializer, $valueHolder, $publicProperties),
new MagicClone($originalClass, $initializer, $valueHolder),
new MagicSleep($originalClass, $initializer, $valueHolder),
new MagicWakeup($originalClass),
new SetProxyInitializer($initializer),
new GetProxyInitializer($initializer),
new InitializeProxy($initializer, $valueHolder),
new IsProxyInitialized($valueHolder),
new GetWrappedValueHolderValue($valueHolder),
]
)
);
}
private function buildLazyLoadingMethodInterceptor(
InitializerProperty $initializer,
ValueHolderProperty $valueHolder
): callable {
return static function (ReflectionMethod $method) use ($initializer, $valueHolder): LazyLoadingMethodInterceptor {
return LazyLoadingMethodInterceptor::generateMethod(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()),
$initializer,
$valueHolder
);
};
}
}
src/ProxyManager/ProxyGenerator/NullObject/MethodGenerator/NullObjectMethodInterceptor.php 0000644 00000001504 13721511157 0026224 0 ustar 00 returnsReference()) {
$reference = IdentifierSuffixer::getIdentifier('ref');
$method->setBody("\$reference = null;\nreturn \$" . $reference . ';');
}
return $method;
}
}
src/ProxyManager/ProxyGenerator/NullObject/MethodGenerator/StaticProxyConstructor.php 0000644 00000003235 13721511157 0025345 0 ustar 00 ' . $publicProperty->getName() . ' = null;';
},
Properties::fromReflectionClass($originalClass)
->onlyNullableProperties()
->getPublicProperties()
);
$this->setReturnType($originalClass->getName());
$this->setDocBlock('Constructor for null object initialization');
$this->setBody(
'static $reflection;' . "\n\n"
. '$reflection = $reflection ?? new \ReflectionClass(__CLASS__);' . "\n"
. '$instance = $reflection->newInstanceWithoutConstructor();' . "\n\n"
. ($nullableProperties ? implode("\n", $nullableProperties) . "\n\n" : '')
. 'return $instance;'
);
}
}
src/ProxyManager/ProxyGenerator/NullObjectGenerator.php 0000644 00000003746 13721511157 0017375 0 ustar 00 isInterface()) {
$interfaces[] = $originalClass->getName();
} else {
$classGenerator->setExtendedClass($originalClass->getName());
}
$classGenerator->setImplementedInterfaces($interfaces);
foreach (ProxiedMethodsFilter::getProxiedMethods($originalClass, []) as $method) {
$classGenerator->addMethodFromGenerator(
NullObjectMethodInterceptor::generateMethod(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName())
)
);
}
ClassGeneratorUtils::addMethodIfNotFinal(
$originalClass,
$classGenerator,
new StaticProxyConstructor($originalClass)
);
}
}
src/ProxyManager/ProxyGenerator/PropertyGenerator/PublicPropertiesMap.php 0000644 00000002261 13721511157 0023100 0 ustar 00 */
private array $publicProperties = [];
/**
* @throws InvalidArgumentException
*/
public function __construct(Properties $properties)
{
parent::__construct(IdentifierSuffixer::getIdentifier('publicProperties'));
foreach ($properties->getPublicProperties() as $publicProperty) {
$this->publicProperties[$publicProperty->getName()] = true;
}
$this->setDefaultValue($this->publicProperties);
$this->setVisibility(self::VISIBILITY_PRIVATE);
$this->setStatic(true);
$this->setDocBlock('@var bool[] map of public properties of the parent class');
}
public function isEmpty(): bool
{
return ! $this->publicProperties;
}
}
src/ProxyManager/ProxyGenerator/ProxyGeneratorInterface.php 0000644 00000001052 13721511157 0020262 0 ustar 00 setDocBlock('@param string $name');
$this->setBody(
'$return = $this->' . $adapterProperty->getName() . '->call(' . var_export($originalClass->getName(), true)
. ', \'__get\', array($name));' . "\n\n" . 'return $return;'
);
}
}
src/ProxyManager/ProxyGenerator/RemoteObject/MethodGenerator/MagicIsset.php 0000644 00000002014 13721511157 0023151 0 ustar 00 setDocBlock('@param string $name');
$this->setBody(
'$return = $this->' . $adapterProperty->getName() . '->call(' . var_export($originalClass->getName(), true)
. ', \'__isset\', array($name));' . "\n\n"
. 'return $return;'
);
}
}
src/ProxyManager/ProxyGenerator/RemoteObject/MethodGenerator/MagicSet.php 0000644 00000002153 13721511157 0022621 0 ustar 00 setDocBlock('@param string \$name\n@param mixed \$value');
$this->setBody(
'$return = $this->' . $adapterProperty->getName() . '->call(' . var_export($originalClass->getName(), true)
. ', \'__set\', array($name, $value));' . "\n\n"
. 'return $return;'
);
}
}
src/ProxyManager/ProxyGenerator/RemoteObject/MethodGenerator/MagicUnset.php 0000644 00000002014 13721511157 0023160 0 ustar 00 setDocBlock('@param string $name');
$this->setBody(
'$return = $this->' . $adapterProperty->getName() . '->call(' . var_export($originalClass->getName(), true)
. ', \'__unset\', array($name));' . "\n\n"
. 'return $return;'
);
}
}
src/ProxyManager/ProxyGenerator/RemoteObject/MethodGenerator/RemoteObjectMethod.php 0000644 00000005014 13721511157 0024647 0 ustar 00 ' . $adapterProperty->getName()
. '->call(' . var_export($originalClass->getName(), true)
. ', ' . var_export($originalMethod->getName(), true) . ', $args);' . "\n\n"
. ProxiedMethodReturnExpression::generate('$return', $originalMethod);
$defaultValues = self::getDefaultValuesForMethod($originalMethod);
$declaredParameterCount = count($originalMethod->getParameters());
$method->setBody(
strtr(
self::TEMPLATE,
[
'#PROXIED_RETURN#' => $proxiedReturn,
'#DEFAULT_VALUES#' => var_export($defaultValues, true),
'#PARAMETER_COUNT#' => var_export($declaredParameterCount, true),
]
)
);
return $method;
}
/** @psalm-return list */
private static function getDefaultValuesForMethod(MethodReflection $originalMethod): array
{
$defaultValues = [];
foreach ($originalMethod->getParameters() as $parameter) {
if ($parameter->isOptional() && $parameter->isDefaultValueAvailable()) {
/** @psalm-var int|float|bool|array|string|null */
$defaultValues[] = $parameter->getDefaultValue();
continue;
}
if ($parameter->isVariadic()) {
continue;
}
$defaultValues[] = null;
}
return $defaultValues;
}
}
src/ProxyManager/ProxyGenerator/RemoteObject/MethodGenerator/StaticProxyConstructor.php 0000644 00000003345 13721511157 0025670 0 ustar 00 getName();
parent::__construct(
'staticProxyConstructor',
[new ParameterGenerator($adapterName, AdapterInterface::class)],
MethodGenerator::FLAG_PUBLIC | MethodGenerator::FLAG_STATIC,
null,
'Constructor for remote object control\n\n'
. '@param \\ProxyManager\\Factory\\RemoteObject\\AdapterInterface \$adapter'
);
$body = 'static $reflection;' . "\n\n"
. '$reflection = $reflection ?? new \ReflectionClass(__CLASS__);' . "\n"
. '$instance = $reflection->newInstanceWithoutConstructor();' . "\n\n"
. '$instance->' . $adapterName . ' = $' . $adapterName . ";\n\n"
. UnsetPropertiesGenerator::generateSnippet(Properties::fromReflectionClass($originalClass), 'instance');
$this->setBody($body . "\n\nreturn \$instance;");
}
}
src/ProxyManager/ProxyGenerator/RemoteObject/PropertyGenerator/AdapterProperty.php 0000644 00000001427 13721511157 0024661 0 ustar 00 setVisibility(self::VISIBILITY_PRIVATE);
$this->setDocBlock('@var \\' . AdapterInterface::class . ' Remote web service adapter');
}
}
src/ProxyManager/ProxyGenerator/RemoteObjectGenerator.php 0000644 00000006517 13721511157 0017715 0 ustar 00 isInterface()) {
$interfaces[] = $originalClass->getName();
} else {
$classGenerator->setExtendedClass($originalClass->getName());
}
$classGenerator->setImplementedInterfaces($interfaces);
$classGenerator->addPropertyFromGenerator($adapter = new AdapterProperty());
array_map(
static function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator): void {
ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
},
array_merge(
array_map(
static function (ReflectionMethod $method) use ($adapter, $originalClass): RemoteObjectMethod {
return RemoteObjectMethod::generateMethod(
new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()),
$adapter,
$originalClass
);
},
ProxiedMethodsFilter::getProxiedMethods(
$originalClass,
['__get', '__set', '__isset', '__unset']
)
),
[
new StaticProxyConstructor($originalClass, $adapter),
new MagicGet($originalClass, $adapter),
new MagicSet($originalClass, $adapter),
new MagicIsset($originalClass, $adapter),
new MagicUnset($originalClass, $adapter),
]
)
);
}
}
src/ProxyManager/ProxyGenerator/Util/GetMethodIfExists.php 0000644 00000000737 13721511157 0017736 0 ustar 00 hasMethod($method) ? $class->getMethod($method) : null;
}
}
src/ProxyManager/ProxyGenerator/Util/Properties.php 0000644 00000015121 13721511157 0016524 0 ustar 00 properties = $properties;
}
public static function fromReflectionClass(ReflectionClass $reflection): self
{
$class = $reflection;
$parentClasses = [];
do {
$parentClasses[] = $class;
$class = $class->getParentClass();
} while ($class);
return new self(array_merge(
...array_map(static function (ReflectionClass $class): array {
return array_values(array_filter(
$class->getProperties(),
static function (ReflectionProperty $property) use ($class): bool {
return $class->getName() === $property->getDeclaringClass()->getName()
&& ! $property->isStatic();
}
));
}, $parentClasses)
));
}
/**
* @param array $excludedProperties
*/
public function filter(array $excludedProperties): self
{
$properties = $this->getInstanceProperties();
foreach ($excludedProperties as $propertyName) {
unset($properties[$propertyName]);
}
return new self($properties);
}
public function onlyNonReferenceableProperties(): self
{
return new self(array_filter($this->properties, static function (ReflectionProperty $property): bool {
if (! $property->hasType()) {
return false;
}
return ! array_key_exists(
$property->getName(),
// https://bugs.php.net/bug.php?id=77673
array_flip(array_keys($property->getDeclaringClass()->getDefaultProperties()))
);
}));
}
/** @deprecated Since PHP 7.4.1, all properties can be unset, regardless if typed or not */
public function onlyPropertiesThatCanBeUnset(): self
{
return $this;
}
/**
* Properties that cannot be referenced are non-nullable typed properties that aren't initialised
*/
public function withoutNonReferenceableProperties(): self
{
return new self(array_filter($this->properties, static function (ReflectionProperty $property): bool {
if (! $property->hasType()) {
return true;
}
$type = $property->getType();
assert($type instanceof ReflectionType);
if ($type->allowsNull()) {
return true;
}
return array_key_exists(
$property->getName(),
// https://bugs.php.net/bug.php?id=77673
array_flip(array_keys($property->getDeclaringClass()->getDefaultProperties()))
);
}));
}
public function onlyNullableProperties(): self
{
return new self(array_filter(
$this->properties,
static function (ReflectionProperty $property): bool {
$type = $property->getType();
assert($type instanceof ReflectionType || $type === null);
return $type === null || $type->allowsNull();
}
));
}
public function onlyInstanceProperties(): self
{
return new self(array_values(array_merge($this->getAccessibleProperties(), $this->getPrivateProperties())));
}
public function empty(): bool
{
return $this->properties === [];
}
/**
* @return array indexed by the property internal visibility-aware name
*/
public function getPublicProperties(): array
{
$publicProperties = [];
foreach ($this->properties as $property) {
if (! $property->isPublic()) {
continue;
}
$publicProperties[$property->getName()] = $property;
}
return $publicProperties;
}
/**
* @return array indexed by the property internal visibility-aware name (\0*\0propertyName)
*/
public function getProtectedProperties(): array
{
$protectedProperties = [];
foreach ($this->properties as $property) {
if (! $property->isProtected()) {
continue;
}
$protectedProperties["\0*\0" . $property->getName()] = $property;
}
return $protectedProperties;
}
/**
* @return array indexed by the property internal visibility-aware name (\0ClassName\0propertyName)
*/
public function getPrivateProperties(): array
{
$privateProperties = [];
foreach ($this->properties as $property) {
if (! $property->isPrivate()) {
continue;
}
$declaringClass = $property->getDeclaringClass()->getName();
$privateProperties["\0" . $declaringClass . "\0" . $property->getName()] = $property;
}
return $privateProperties;
}
/**
* @return array indexed by the property internal visibility-aware name (\0*\0propertyName)
*/
public function getAccessibleProperties(): array
{
return array_merge($this->getPublicProperties(), $this->getProtectedProperties());
}
/**
* @return array> indexed by class name and property name
*/
public function getGroupedPrivateProperties(): array
{
$propertiesMap = [];
foreach ($this->getPrivateProperties() as $property) {
$propertiesMap[$property->getDeclaringClass()->getName()][$property->getName()] = $property;
}
return $propertiesMap;
}
/**
* @return array indexed by the property internal visibility-aware name (\0*\0propertyName)
*/
public function getInstanceProperties(): array
{
return array_merge($this->getAccessibleProperties(), $this->getPrivateProperties());
}
}
src/ProxyManager/ProxyGenerator/Util/ProxiedMethodsFilter.php 0000644 00000004627 13721511157 0020505 0 ustar 00 */
private static array $defaultExcluded = [
'__get',
'__set',
'__isset',
'__unset',
'__clone',
'__sleep',
'__wakeup',
];
/**
* @param ReflectionClass $class reflection class from which methods should be extracted
* @param array $excluded methods to be ignored
*
* @return ReflectionMethod[]
*/
public static function getProxiedMethods(ReflectionClass $class, ?array $excluded = null): array
{
return self::doFilter($class, $excluded ?? self::$defaultExcluded);
}
/**
* @param ReflectionClass $class reflection class from which methods should be extracted
* @param array $excluded methods to be ignored
*
* @return ReflectionMethod[]
*/
public static function getAbstractProxiedMethods(ReflectionClass $class, ?array $excluded = null): array
{
return self::doFilter($class, $excluded ?? self::$defaultExcluded, true);
}
/**
* @param array $excluded
*
* @return array
*/
private static function doFilter(ReflectionClass $class, array $excluded, bool $requireAbstract = false): array
{
$ignored = array_flip(array_map('strtolower', $excluded));
return array_values(array_filter(
$class->getMethods(ReflectionMethod::IS_PUBLIC),
static function (ReflectionMethod $method) use ($ignored, $requireAbstract): bool {
return (! $requireAbstract || $method->isAbstract()) && ! (
array_key_exists(strtolower($method->getName()), $ignored)
|| self::methodCannotBeProxied($method)
);
}
));
}
/**
* Checks whether the method cannot be proxied
*/
private static function methodCannotBeProxied(ReflectionMethod $method): bool
{
return $method->isConstructor() || $method->isFinal() || $method->isStatic();
}
}
src/ProxyManager/ProxyGenerator/Util/PublicScopeSimulator.php 0000644 00000014521 13721511157 0020503 0 ustar 00 ' . $valueHolder->getName();
}
return '$realInstanceReflection = new \\ReflectionClass(get_parent_class($this));' . "\n\n"
. 'if (! $realInstanceReflection->hasProperty($' . $nameParameter . ')) {' . "\n"
. ' $targetObject = ' . $target . ';' . "\n\n"
. self::getUndefinedPropertyNotice($operationType, $nameParameter)
. ' ' . self::getOperation($operationType, $nameParameter, $valueParameter) . "\n"
. " return;\n"
. '}' . "\n\n"
. '$targetObject = ' . self::getTargetObject($valueHolder) . ";\n"
. '$accessor = function ' . $byRef . '() use ($targetObject, $name' . $value . ') {' . "\n"
. ' ' . self::getOperation($operationType, $nameParameter, $valueParameter) . "\n"
. "};\n"
. self::getScopeReBind()
. (
$returnPropertyName
? '$' . $returnPropertyName . ' = ' . $byRef . '$accessor();'
: '$returnValue = ' . $byRef . '$accessor();' . "\n\n" . 'return $returnValue;'
);
}
/**
* This will generate code that triggers a notice if access is attempted on a non-existing property
*/
private static function getUndefinedPropertyNotice(string $operationType, string $nameParameter): string
{
if ($operationType !== self::OPERATION_GET) {
return '';
}
return ' $backtrace = debug_backtrace(false);' . "\n"
. ' trigger_error(' . "\n"
. ' sprintf(' . "\n"
. ' \'Undefined property: %s::$%s in %s on line %s\',' . "\n"
. ' get_parent_class($this),' . "\n"
. ' $' . $nameParameter . ',' . "\n"
. ' $backtrace[0][\'file\'],' . "\n"
. ' $backtrace[0][\'line\']' . "\n"
. ' ),' . "\n"
. ' \E_USER_NOTICE' . "\n"
. ' );' . "\n";
}
/**
* Defines whether the given operation produces a reference.
*
* Note: if the object is a wrapper, the wrapped instance is accessed directly. If the object
* is a ghost or the proxy has no wrapper, then an instance of the parent class is created via
* on-the-fly unserialization
*/
private static function getByRefReturnValue(string $operationType): string
{
return $operationType === self::OPERATION_GET || $operationType === self::OPERATION_SET ? '& ' : '';
}
/**
* Retrieves the logic to fetch the object on which access should be attempted
*/
private static function getTargetObject(?PropertyGenerator $valueHolder = null): string
{
if ($valueHolder) {
return '$this->' . $valueHolder->getName();
}
return '$realInstanceReflection->newInstanceWithoutConstructor()';
}
/**
* @throws InvalidArgumentException
*/
private static function getOperation(string $operationType, string $nameParameter, ?string $valueParameter): string
{
switch ($operationType) {
case self::OPERATION_GET:
return 'return $targetObject->$' . $nameParameter . ';';
case self::OPERATION_SET:
if ($valueParameter === null) {
throw new InvalidArgumentException('Parameter $valueParameter not provided');
}
return 'return $targetObject->$' . $nameParameter . ' = $' . $valueParameter . ';';
case self::OPERATION_ISSET:
return 'return isset($targetObject->$' . $nameParameter . ');';
case self::OPERATION_UNSET:
return 'unset($targetObject->$' . $nameParameter . ');';
}
throw new InvalidArgumentException(sprintf('Invalid operation "%s" provided', $operationType));
}
/**
* Generates code to bind operations to the parent scope
*/
private static function getScopeReBind(): string
{
return '$backtrace = debug_backtrace(true);' . "\n"
. '$scopeObject = isset($backtrace[1][\'object\'])'
. ' ? $backtrace[1][\'object\'] : new \ProxyManager\Stub\EmptyClassStub();' . "\n"
. '$accessor = $accessor->bindTo($scopeObject, get_class($scopeObject));' . "\n";
}
}
src/ProxyManager/ProxyGenerator/Util/UnsetPropertiesGenerator.php 0000644 00000006022 13721511157 0021412 0 ustar 00 __invoke($%s);
PHP;
public static function generateSnippet(Properties $properties, string $instanceName): string
{
return self::generateUnsetAccessiblePropertiesCode($properties, $instanceName)
. self::generateUnsetPrivatePropertiesCode($properties, $instanceName);
}
private static function generateUnsetAccessiblePropertiesCode(Properties $properties, string $instanceName): string
{
$accessibleProperties = $properties->getAccessibleProperties();
if (! $accessibleProperties) {
return '';
}
return self::generateUnsetStatement($accessibleProperties, $instanceName) . "\n\n";
}
private static function generateUnsetPrivatePropertiesCode(Properties $properties, string $instanceName): string
{
$groups = $properties->getGroupedPrivateProperties();
if (! $groups) {
return '';
}
$unsetClosureCalls = [];
foreach ($groups as $privateProperties) {
$firstProperty = reset($privateProperties);
assert($firstProperty instanceof ReflectionProperty);
$unsetClosureCalls[] = self::generateUnsetClassPrivatePropertiesBlock(
$firstProperty->getDeclaringClass(),
$privateProperties,
$instanceName
);
}
return implode("\n\n", $unsetClosureCalls) . "\n\n";
}
/** @param array $properties */
private static function generateUnsetClassPrivatePropertiesBlock(
ReflectionClass $declaringClass,
array $properties,
string $instanceName
): string {
$declaringClassName = $declaringClass->getName();
return sprintf(
self::CLOSURE_TEMPLATE,
$declaringClassName,
self::generateUnsetStatement($properties, 'instance'),
$instanceName,
var_export($declaringClassName, true),
$instanceName
);
}
/** @param array $properties */
private static function generateUnsetStatement(array $properties, string $instanceName): string
{
return 'unset('
. implode(
', ',
array_map(
static function (ReflectionProperty $property) use ($instanceName): string {
return '$' . $instanceName . '->' . $property->getName();
},
$properties
)
)
. ');';
}
}
src/ProxyManager/ProxyGenerator/ValueHolder/MethodGenerator/Constructor.php 0000644 00000006210 13721511157 0023300 0 ustar 00 setBody(
'static $reflection;' . "\n\n"
. 'if (! $this->' . $valueHolder->getName() . ') {' . "\n"
. ' $reflection = $reflection ?: new \ReflectionClass('
. var_export($originalClass->getName(), true)
. ");\n"
. ' $this->' . $valueHolder->getName() . ' = $reflection->newInstanceWithoutConstructor();' . "\n"
. UnsetPropertiesGenerator::generateSnippet(Properties::fromReflectionClass($originalClass), 'this')
. '}'
. ($originalConstructor ? self::generateOriginalConstructorCall($originalConstructor, $valueHolder) : '')
);
return $constructor;
}
private static function generateOriginalConstructorCall(
MethodReflection $originalConstructor,
PropertyGenerator $valueHolder
): string {
return "\n\n"
. '$this->' . $valueHolder->getName() . '->' . $originalConstructor->getName() . '('
. implode(
', ',
array_map(
static function (ParameterReflection $parameter): string {
return ($parameter->isVariadic() ? '...' : '') . '$' . $parameter->getName();
},
$originalConstructor->getParameters()
)
)
. ');';
}
private static function getConstructor(ReflectionClass $class): ?MethodReflection
{
$constructors = array_map(
static function (ReflectionMethod $method): MethodReflection {
return new MethodReflection(
$method->getDeclaringClass()->getName(),
$method->getName()
);
},
array_filter(
$class->getMethods(),
static function (ReflectionMethod $method): bool {
return $method->isConstructor();
}
)
);
return reset($constructors) ?: null;
}
}
src/ProxyManager/ProxyGenerator/ValueHolder/MethodGenerator/GetWrappedValueHolderValue.php 0000644 00000001453 13721511157 0026151 0 ustar 00 setBody('return $this->' . $valueHolderProperty->getName() . ';');
$this->setReturnType('?object');
}
}
src/ProxyManager/ProxyGenerator/ValueHolder/MethodGenerator/MagicSleep.php 0000644 00000001216 13721511157 0022765 0 ustar 00 setBody('return array(' . var_export($valueHolderProperty->getName(), true) . ');');
}
}
src/ProxyManager/Signature/ClassSignatureGenerator.php 0000644 00000002134 13721511157 0017222 0 ustar 00 signatureGenerator = $signatureGenerator;
}
/**
* {@inheritDoc}
*
* @throws InvalidArgumentException
*/
public function addSignature(ClassGenerator $classGenerator, array $parameters): ClassGenerator
{
$classGenerator->addPropertyFromGenerator(new PropertyGenerator(
'signature' . $this->signatureGenerator->generateSignatureKey($parameters),
$this->signatureGenerator->generateSignature($parameters),
PropertyGenerator::FLAG_STATIC | PropertyGenerator::FLAG_PRIVATE
));
return $classGenerator;
}
}
src/ProxyManager/Signature/ClassSignatureGeneratorInterface.php 0000644 00000000672 13721511157 0021050 0 ustar 00 $parameters
*/
public function addSignature(ClassGenerator $classGenerator, array $parameters): ClassGenerator;
}
src/ProxyManager/Signature/Exception/ExceptionInterface.php 0000644 00000000273 13721511157 0020143 0 ustar 00 getName(),
$expected,
count($parameters)
));
}
}
src/ProxyManager/Signature/Exception/MissingSignatureException.php 0000644 00000001300 13721511157 0021526 0 ustar 00 getName(),
$expected,
count($parameters)
));
}
}
src/ProxyManager/Signature/SignatureChecker.php 0000644 00000003015 13721511157 0015651 0 ustar 00 signatureGenerator = $signatureGenerator;
}
/**
* {@inheritDoc}
*/
public function checkSignature(ReflectionClass $class, array $parameters): void
{
$propertyName = 'signature' . $this->signatureGenerator->generateSignatureKey($parameters);
$signature = $this->signatureGenerator->generateSignature($parameters);
$defaultProperties = $class->getDefaultProperties();
if (! (array_key_exists($propertyName, $defaultProperties) && is_string($defaultProperties[$propertyName]))) {
throw MissingSignatureException::fromMissingSignature($class, $parameters, $signature);
}
if ($defaultProperties[$propertyName] !== $signature) {
throw InvalidSignatureException::fromInvalidSignature(
$class,
$parameters,
$defaultProperties[$propertyName],
$signature
);
}
}
}
src/ProxyManager/Signature/SignatureCheckerInterface.php 0000644 00000001207 13721511157 0017473 0 ustar 00 $parameters
*
* @throws InvalidSignatureException
* @throws MissingSignatureException
*/
public function checkSignature(ReflectionClass $class, array $parameters): void;
}
src/ProxyManager/Signature/SignatureGenerator.php 0000644 00000001546 13721511157 0016242 0 ustar 00 parameterEncoder = new ParameterEncoder();
$this->parameterHasher = new ParameterHasher();
}
/**
* {@inheritDoc}
*/
public function generateSignature(array $parameters): string
{
return $this->parameterEncoder->encodeParameters($parameters);
}
/**
* {@inheritDoc}
*/
public function generateSignatureKey(array $parameters): string
{
return $this->parameterHasher->hashParameters($parameters);
}
}
src/ProxyManager/Signature/SignatureGeneratorInterface.php 0000644 00000001173 13721511157 0020057 0 ustar 00 $parameters
*/
public function generateSignature(array $parameters): string;
/**
* Generates a signature key to be looked up when verifying generated code validity
*
* @param array $parameters
*/
public function generateSignatureKey(array $parameters): string;
}
src/ProxyManager/Stub/EmptyClassStub.php 0000644 00000000212 13721511157 0014315 0 ustar 00 @,
* where the detected version is what composer could detect.
*
* @throws OutOfBoundsException
*
* @psalm-pure
*
* @psalm-suppress MixedOperand `composer-runtime-api:^2` has rough if no type declarations at all - we'll live with it
* @psalm-suppress ImpureMethodCall `composer-runtime-api:^2` has rough if no type declarations at all - we'll live with it
*/
public static function getVersion(): string
{
return InstalledVersions::getPrettyVersion('ocramius/proxy-manager')
. '@' . InstalledVersions::getReference('ocramius/proxy-manager');
}
}