CONTRIBUTING.md000064400000002073144760125520007005 0ustar00# Contributing * Coding standard for the project is [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) * The project will follow strict [object calisthenics](http://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php) * Any contribution must provide tests for additional introduced conditions * Any un-confirmed issue needs a failing test case before being accepted * Pull requests must be sent from a new hotfix/feature branch, not from `master`. ## Installation To install the project and run the tests, you need to clone it first: ```sh $ git clone git://github.com/doctrine/instantiator.git ``` You will then need to run a composer installation: ```sh $ cd Instantiator $ curl -s https://getcomposer.org/installer | php $ php composer.phar update ``` ## Testing The PHPUnit version to be used is the one installed as a dev- dependency via composer: ```sh $ ./vendor/bin/phpunit ``` Accepted coverage for new contributions is 80%. Any contribution not satisfying this requirement won't be merged. LICENSE000064400000002044144760125520005557 0ustar00Copyright (c) 2014 Doctrine Project 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.md000064400000003573144760125520006041 0ustar00# Instantiator This library provides a way of avoiding usage of constructors when instantiating PHP classes. [![Build Status](https://travis-ci.org/doctrine/instantiator.svg?branch=master)](https://travis-ci.org/doctrine/instantiator) [![Code Coverage](https://scrutinizer-ci.com/g/doctrine/instantiator/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/doctrine/instantiator/?branch=master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/doctrine/instantiator/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/doctrine/instantiator/?branch=master) [![Dependency Status](https://www.versioneye.com/package/php--doctrine--instantiator/badge.svg)](https://www.versioneye.com/package/php--doctrine--instantiator) [![HHVM Status](http://hhvm.h4cc.de/badge/doctrine/instantiator.png)](http://hhvm.h4cc.de/package/doctrine/instantiator) [![Latest Stable Version](https://poser.pugx.org/doctrine/instantiator/v/stable.png)](https://packagist.org/packages/doctrine/instantiator) [![Latest Unstable Version](https://poser.pugx.org/doctrine/instantiator/v/unstable.png)](https://packagist.org/packages/doctrine/instantiator) ## Installation The suggested installation method is via [composer](https://getcomposer.org/): ```sh php composer.phar require "doctrine/instantiator:~1.0.3" ``` ## Usage The instantiator is able to create new instances of any class without using the constructor or any API of the class itself: ```php $instantiator = new \Doctrine\Instantiator\Instantiator(); $instance = $instantiator->instantiate(\My\ClassName\Here::class); ``` ## Contributing Please read the [CONTRIBUTING.md](CONTRIBUTING.md) contents if you wish to help out! ## Credits This library was migrated from [ocramius/instantiator](https://github.com/Ocramius/Instantiator), which has been donated to the doctrine organization, and which is now deprecated in favour of this package. composer.json000064400000002466144760125520007304 0ustar00{ "name": "doctrine/instantiator", "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", "type": "library", "license": "MIT", "homepage": "https://github.com/doctrine/instantiator", "keywords": [ "instantiate", "constructor" ], "authors": [ { "name": "Marco Pivetta", "email": "ocramius@gmail.com", "homepage": "http://ocramius.github.com/" } ], "require": { "php": "^7.1" }, "require-dev": { "ext-phar": "*", "ext-pdo": "*", "phpunit/phpunit": "^6.2.3", "squizlabs/php_codesniffer": "^3.0.2", "athletic/athletic": "~0.1.8" }, "autoload": { "psr-4": { "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" } }, "autoload-dev": { "psr-0": { "DoctrineTest\\InstantiatorPerformance\\": "tests", "DoctrineTest\\InstantiatorTest\\": "tests", "DoctrineTest\\InstantiatorTestAsset\\": "tests" } }, "extra": { "branch-alias": { "dev-master": "1.2.x-dev" } } } src/Doctrine/Instantiator/Exception/ExceptionInterface.php000064400000002245144760125520020020 0ustar00. */ namespace Doctrine\Instantiator\Exception; /** * Base exception marker interface for the instantiator component * * @author Marco Pivetta */ interface ExceptionInterface { } src/Doctrine/Instantiator/Exception/InvalidArgumentException.php000064400000004144144760125520021211 0ustar00. */ namespace Doctrine\Instantiator\Exception; use InvalidArgumentException as BaseInvalidArgumentException; use ReflectionClass; /** * Exception for invalid arguments provided to the instantiator * * @author Marco Pivetta */ class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface { public static function fromNonExistingClass(string $className) : self { if (interface_exists($className)) { return new self(sprintf('The provided type "%s" is an interface, and can not be instantiated', $className)); } if (PHP_VERSION_ID >= 50400 && trait_exists($className)) { return new self(sprintf('The provided type "%s" is a trait, and can not be instantiated', $className)); } return new self(sprintf('The provided class "%s" does not exist', $className)); } public static function fromAbstractClass(ReflectionClass $reflectionClass) : self { return new self(sprintf( 'The provided class "%s" is abstract, and can not be instantiated', $reflectionClass->getName() )); } } src/Doctrine/Instantiator/Exception/UnexpectedValueException.php000064400000004555144760125520021227 0ustar00. */ namespace Doctrine\Instantiator\Exception; use Exception; use ReflectionClass; use UnexpectedValueException as BaseUnexpectedValueException; /** * Exception for given parameters causing invalid/unexpected state on instantiation * * @author Marco Pivetta */ class UnexpectedValueException extends BaseUnexpectedValueException implements ExceptionInterface { public static function fromSerializationTriggeredException( ReflectionClass $reflectionClass, Exception $exception ) : self { return new self( sprintf( 'An exception was raised while trying to instantiate an instance of "%s" via un-serialization', $reflectionClass->getName() ), 0, $exception ); } public static function fromUncleanUnSerialization( ReflectionClass $reflectionClass, string $errorString, int $errorCode, string $errorFile, int $errorLine ) : self { return new self( sprintf( 'Could not produce an instance of "%s" via un-serialization, since an error was triggered ' . 'in file "%s" at line "%d"', $reflectionClass->getName(), $errorFile, $errorLine ), 0, new Exception($errorString, $errorCode) ); } } src/Doctrine/Instantiator/Instantiator.php000064400000015177144760125520014772 0ustar00. */ namespace Doctrine\Instantiator; use Doctrine\Instantiator\Exception\InvalidArgumentException; use Doctrine\Instantiator\Exception\UnexpectedValueException; use Exception; use ReflectionClass; /** * {@inheritDoc} * * @author Marco Pivetta */ final class Instantiator implements InstantiatorInterface { /** * Markers used internally by PHP to define whether {@see \unserialize} should invoke * the method {@see \Serializable::unserialize()} when dealing with classes implementing * the {@see \Serializable} interface. */ const SERIALIZATION_FORMAT_USE_UNSERIALIZER = 'C'; const SERIALIZATION_FORMAT_AVOID_UNSERIALIZER = 'O'; /** * @var \callable[] used to instantiate specific classes, indexed by class name */ private static $cachedInstantiators = []; /** * @var object[] of objects that can directly be cloned, indexed by class name */ private static $cachedCloneables = []; /** * {@inheritDoc} */ public function instantiate($className) { if (isset(self::$cachedCloneables[$className])) { return clone self::$cachedCloneables[$className]; } if (isset(self::$cachedInstantiators[$className])) { $factory = self::$cachedInstantiators[$className]; return $factory(); } return $this->buildAndCacheFromFactory($className); } /** * Builds the requested object and caches it in static properties for performance * * @return object */ private function buildAndCacheFromFactory(string $className) { $factory = self::$cachedInstantiators[$className] = $this->buildFactory($className); $instance = $factory(); if ($this->isSafeToClone(new ReflectionClass($instance))) { self::$cachedCloneables[$className] = clone $instance; } return $instance; } /** * Builds a callable capable of instantiating the given $className without * invoking its constructor. * * @throws InvalidArgumentException * @throws UnexpectedValueException * @throws \ReflectionException */ private function buildFactory(string $className) : callable { $reflectionClass = $this->getReflectionClass($className); if ($this->isInstantiableViaReflection($reflectionClass)) { return [$reflectionClass, 'newInstanceWithoutConstructor']; } $serializedString = sprintf( '%s:%d:"%s":0:{}', self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER, strlen($className), $className ); $this->checkIfUnSerializationIsSupported($reflectionClass, $serializedString); return function () use ($serializedString) { return unserialize($serializedString); }; } /** * @param string $className * * @return ReflectionClass * * @throws InvalidArgumentException * @throws \ReflectionException */ private function getReflectionClass($className) : ReflectionClass { if (! class_exists($className)) { throw InvalidArgumentException::fromNonExistingClass($className); } $reflection = new ReflectionClass($className); if ($reflection->isAbstract()) { throw InvalidArgumentException::fromAbstractClass($reflection); } return $reflection; } /** * @param ReflectionClass $reflectionClass * @param string $serializedString * * @throws UnexpectedValueException * * @return void */ private function checkIfUnSerializationIsSupported(ReflectionClass $reflectionClass, $serializedString) : void { set_error_handler(function ($code, $message, $file, $line) use ($reflectionClass, & $error) : void { $error = UnexpectedValueException::fromUncleanUnSerialization( $reflectionClass, $message, $code, $file, $line ); }); $this->attemptInstantiationViaUnSerialization($reflectionClass, $serializedString); restore_error_handler(); if ($error) { throw $error; } } /** * @param ReflectionClass $reflectionClass * @param string $serializedString * * @throws UnexpectedValueException * * @return void */ private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, $serializedString) : void { try { unserialize($serializedString); } catch (Exception $exception) { restore_error_handler(); throw UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $exception); } } private function isInstantiableViaReflection(ReflectionClass $reflectionClass) : bool { return ! ($this->hasInternalAncestors($reflectionClass) && $reflectionClass->isFinal()); } /** * Verifies whether the given class is to be considered internal */ private function hasInternalAncestors(ReflectionClass $reflectionClass) : bool { do { if ($reflectionClass->isInternal()) { return true; } } while ($reflectionClass = $reflectionClass->getParentClass()); return false; } /** * Checks if a class is cloneable * * Classes implementing `__clone` cannot be safely cloned, as that may cause side-effects. */ private function isSafeToClone(ReflectionClass $reflection) : bool { return $reflection->isCloneable() && ! $reflection->hasMethod('__clone'); } } src/Doctrine/Instantiator/InstantiatorInterface.php000064400000002576144760125520016612 0ustar00. */ namespace Doctrine\Instantiator; /** * Instantiator provides utility methods to build objects without invoking their constructors * * @author Marco Pivetta */ interface InstantiatorInterface { /** * @param string $className * * @return object * * @throws \Doctrine\Instantiator\Exception\ExceptionInterface */ public function instantiate($className); }