.doctrine-project.json000064400000001604144760122170010775 0ustar00{ "active": true, "name": "Instantiator", "slug": "instantiator", "docsSlug": "doctrine-instantiator", "codePath": "/src", "versions": [ { "name": "1.4", "branchName": "master", "slug": "latest", "upcoming": true }, { "name": "1.3", "branchName": "1.3.x", "slug": "1.3", "aliases": [ "current", "stable" ], "maintained": true, "current": true }, { "name": "1.2", "branchName": "1.2.x", "slug": "1.2" }, { "name": "1.1", "branchName": "1.1.x", "slug": "1.1" }, { "name": "1.0", "branchName": "1.0.x", "slug": "1.0" } ] } .github/FUNDING.yml000064400000000173144760122170007726 0ustar00patreon: phpdoctrine tidelift: packagist/doctrine%2Finstantiator custom: https://www.doctrine-project.org/sponsorship.html .github/workflows/coding-standards.yml000064400000002202144760122170014110 0ustar00 name: "Coding Standards" on: pull_request: branches: - "*.x" push: branches: - "*.x" env: COMPOSER_ROOT_VERSION: "1.4" jobs: coding-standards: name: "Coding Standards" runs-on: "ubuntu-20.04" strategy: matrix: php-version: - "7.4" steps: - name: "Checkout" uses: "actions/checkout@v2" - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: coverage: "none" php-version: "${{ matrix.php-version }}" tools: "cs2pr" - name: "Cache dependencies installed with Composer" uses: "actions/cache@v2" with: path: "~/.composer/cache" key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" restore-keys: "php-${{ matrix.php-version }}-composer-locked-" - name: "Install dependencies with Composer" run: "composer install --no-interaction --no-progress" # https://github.com/doctrine/.github/issues/3 - name: "Run PHP_CodeSniffer" run: "vendor/bin/phpcs -q --no-colors --report=checkstyle | cs2pr" .github/workflows/continuous-integration.yml000064400000004250144760122170015420 0ustar00 name: "Continuous Integration" on: pull_request: branches: - "*.x" push: branches: - "*.x" env: fail-fast: true COMPOSER_ROOT_VERSION: "1.4" jobs: phpunit: name: "PHPUnit with SQLite" runs-on: "ubuntu-20.04" strategy: matrix: php-version: - "7.1" - "7.2" - "7.3" - "7.4" - "8.0" steps: - name: "Checkout" uses: "actions/checkout@v2" with: fetch-depth: 2 - name: "Install PHP with XDebug" uses: "shivammathur/setup-php@v2" if: "${{ matrix.php-version == '7.1' }}" with: php-version: "${{ matrix.php-version }}" coverage: "xdebug" ini-values: "zend.assertions=1" - name: "Install PHP with PCOV" uses: "shivammathur/setup-php@v2" if: "${{ matrix.php-version != '7.1' }}" with: php-version: "${{ matrix.php-version }}" coverage: "pcov" ini-values: "zend.assertions=1" - name: "Cache dependencies installed with composer" uses: "actions/cache@v2" with: path: "~/.composer/cache" key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" restore-keys: "php-${{ matrix.php-version }}-composer-locked-" - name: "Install dependencies with composer" run: "composer update --no-interaction --no-progress" - name: "Run PHPUnit" run: "vendor/bin/phpunit --coverage-clover=coverage.xml" - name: "Upload coverage file" uses: "actions/upload-artifact@v2" with: name: "phpunit-${{ matrix.php-version }}.coverage" path: "coverage.xml" upload_coverage: name: "Upload coverage to Codecov" runs-on: "ubuntu-20.04" needs: - "phpunit" steps: - name: "Checkout" uses: "actions/checkout@v2" with: fetch-depth: 2 - name: "Download coverage files" uses: "actions/download-artifact@v2" with: path: "reports" - name: "Upload to Codecov" uses: "codecov/codecov-action@v1" with: directory: reports .github/workflows/phpbench.yml000064400000002223144760122170012456 0ustar00 name: "Performance benchmark" on: pull_request: branches: - "*.x" push: branches: - "*.x" env: fail-fast: true COMPOSER_ROOT_VERSION: "1.4" jobs: phpbench: name: "PHPBench" runs-on: "ubuntu-20.04" strategy: matrix: php-version: - "7.4" steps: - name: "Checkout" uses: "actions/checkout@v2" with: fetch-depth: 2 - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: php-version: "${{ matrix.php-version }}" coverage: "pcov" ini-values: "zend.assertions=1" - name: "Cache dependencies installed with composer" uses: "actions/cache@v2" with: path: "~/.composer/cache" key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" restore-keys: "php-${{ matrix.php-version }}-composer-locked-" - name: "Install dependencies with composer" run: "composer update --no-interaction --no-progress" - name: "Run PHPBench" run: "php ./vendor/bin/phpbench run --iterations=3 --warmup=1 --report=aggregate" .github/workflows/release-on-milestone-closed.yml000064400000002747144760122170016200 0ustar00name: "Automatic Releases" on: milestone: types: - "closed" jobs: release: name: "Git tag, release & create merge-up PR" runs-on: "ubuntu-20.04" steps: - name: "Checkout" uses: "actions/checkout@v2" - name: "Release" uses: "laminas/automatic-releases@v1" with: command-name: "laminas:automatic-releases:release" env: "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} - name: "Create Merge-Up Pull Request" uses: "laminas/automatic-releases@v1" with: command-name: "laminas:automatic-releases:create-merge-up-pull-request" env: "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} - name: "Create new milestones" uses: "laminas/automatic-releases@v1" with: command-name: "laminas:automatic-releases:create-milestones" env: "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} .github/workflows/static-analysis.yml000064400000002174144760122170014004 0ustar00 name: "Static Analysis" on: pull_request: branches: - "*.x" push: branches: - "*.x" env: COMPOSER_ROOT_VERSION: "1.4" jobs: static-analysis-phpstan: name: "Static Analysis with PHPStan" runs-on: "ubuntu-20.04" strategy: matrix: php-version: - "7.4" steps: - name: "Checkout code" uses: "actions/checkout@v2" - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: coverage: "none" php-version: "${{ matrix.php-version }}" tools: "cs2pr" - name: "Cache dependencies installed with composer" uses: "actions/cache@v2" with: path: "~/.composer/cache" key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" restore-keys: "php-${{ matrix.php-version }}-composer-locked-" - name: "Install dependencies with composer" run: "composer install --no-interaction --no-progress" - name: "Run a static analysis with phpstan/phpstan" run: "vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr" CONTRIBUTING.md000064400000002010144760122170006772 0ustar00# Contributing * Follow the [Doctrine Coding Standard](https://github.com/doctrine/coding-standard) * 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. LICENSE000064400000002044144760122170005555 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.md000064400000003075144760122170006034 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://codecov.io/gh/doctrine/instantiator/branch/master/graph/badge.svg)](https://codecov.io/gh/doctrine/instantiator/branch/master) [![Dependency Status](https://www.versioneye.com/package/php--doctrine--instantiator/badge.svg)](https://www.versioneye.com/package/php--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.json000064400000002550144760122170007274 0ustar00{ "name": "doctrine/instantiator", "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", "type": "library", "license": "MIT", "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "instantiate", "constructor" ], "authors": [ { "name": "Marco Pivetta", "email": "ocramius@gmail.com", "homepage": "https://ocramius.github.io/" } ], "require": { "php": "^7.1 || ^8.0" }, "require-dev": { "ext-phar": "*", "ext-pdo": "*", "doctrine/coding-standard": "^8.0", "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", "phpstan/phpstan": "^0.12", "phpstan/phpstan-phpunit": "^0.12", "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "autoload": { "psr-4": { "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" } }, "autoload-dev": { "psr-0": { "DoctrineTest\\InstantiatorPerformance\\": "tests", "DoctrineTest\\InstantiatorTest\\": "tests", "DoctrineTest\\InstantiatorTestAsset\\": "tests" } } } docs/en/index.rst000064400000003337144760122170007751 0ustar00Introduction ============ This library provides a way of avoiding usage of constructors when instantiating PHP classes. Installation ============ The suggested installation method is via `composer`_: .. code-block:: console $ composer require doctrine/instantiator Usage ===== The instantiator is able to create new instances of any class without using the constructor or any API of the class itself: .. code-block:: php instantiate(User::class); Contributing ============ - Follow the `Doctrine Coding Standard`_ - The project will follow strict `object calisthenics`_ - 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``. Testing ======= The PHPUnit version to be used is the one installed as a dev- dependency via composer: .. code-block:: console $ ./vendor/bin/phpunit Accepted coverage for new contributions is 80%. Any contribution not satisfying this requirement won’t be merged. Credits ======= This library was migrated from `ocramius/instantiator`_, which has been donated to the doctrine organization, and which is now deprecated in favour of this package. .. _composer: https://getcomposer.org/ .. _CONTRIBUTING.md: CONTRIBUTING.md .. _ocramius/instantiator: https://github.com/Ocramius/Instantiator .. _Doctrine Coding Standard: https://github.com/doctrine/coding-standard .. _object calisthenics: http://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php docs/en/sidebar.rst000064400000000046144760122170010245 0ustar00.. toctree:: :depth: 3 index phpbench.json000064400000000145144760122170007232 0ustar00{ "bootstrap": "vendor/autoload.php", "path": "tests/DoctrineTest/InstantiatorPerformance" } phpcs.xml.dist000064400000004141144760122170007351 0ustar00 src tests */src/* */src/* tests/DoctrineTest/InstantiatorTestAsset/AbstractClassAsset.php src/Doctrine/Instantiator/Exception/UnexpectedValueException.php src/Doctrine/Instantiator/Exception/InvalidArgumentException.php src/Doctrine/Instantiator/Exception/ExceptionInterface.php src/Doctrine/Instantiator/InstantiatorInterface.php phpstan.neon.dist000064400000000635144760122170010054 0ustar00includes: - vendor/phpstan/phpstan-phpunit/extension.neon - vendor/phpstan/phpstan-phpunit/rules.neon parameters: level: max paths: - src - tests ignoreErrors: # dynamic properties confuse static analysis - message: '#Access to an undefined property object::\$foo\.#' path: '*/tests/DoctrineTest/InstantiatorTest/InstantiatorTest.php' src/Doctrine/Instantiator/Exception/ExceptionInterface.php000064400000000300144760122170020004 0ustar00 $reflectionClass */ 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.php000064400000003111144760122170021210 0ustar00 $reflectionClass */ 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 ); } /** * @template T of object * @phpstan-param ReflectionClass $reflectionClass */ 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.php000064400000015321144760122170014757 0ustar00buildAndCacheFromFactory($className); } /** * Builds the requested object and caches it in static properties for performance * * @return object * * @template T of object * @phpstan-param class-string $className * * @phpstan-return T */ 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 * * @template T of object * @phpstan-param class-string $className * * @phpstan-return callable(): T */ private function buildFactory(string $className): callable { $reflectionClass = $this->getReflectionClass($className); if ($this->isInstantiableViaReflection($reflectionClass)) { return [$reflectionClass, 'newInstanceWithoutConstructor']; } $serializedString = sprintf( '%s:%d:"%s":0:{}', is_subclass_of($className, Serializable::class) ? self::SERIALIZATION_FORMAT_USE_UNSERIALIZER : self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER, strlen($className), $className ); $this->checkIfUnSerializationIsSupported($reflectionClass, $serializedString); return static function () use ($serializedString) { return unserialize($serializedString); }; } /** * @throws InvalidArgumentException * @throws ReflectionException * * @template T of object * @phpstan-param class-string $className * * @phpstan-return ReflectionClass */ private function getReflectionClass(string $className): ReflectionClass { if (! class_exists($className)) { throw InvalidArgumentException::fromNonExistingClass($className); } $reflection = new ReflectionClass($className); if ($reflection->isAbstract()) { throw InvalidArgumentException::fromAbstractClass($reflection); } return $reflection; } /** * @throws UnexpectedValueException * * @template T of object * @phpstan-param ReflectionClass $reflectionClass */ private function checkIfUnSerializationIsSupported(ReflectionClass $reflectionClass, string $serializedString): void { set_error_handler(static function (int $code, string $message, string $file, int $line) use ($reflectionClass, &$error): bool { $error = UnexpectedValueException::fromUncleanUnSerialization( $reflectionClass, $message, $code, $file, $line ); return true; }); try { $this->attemptInstantiationViaUnSerialization($reflectionClass, $serializedString); } finally { restore_error_handler(); } if ($error) { throw $error; } } /** * @throws UnexpectedValueException * * @template T of object * @phpstan-param ReflectionClass $reflectionClass */ private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, string $serializedString): void { try { unserialize($serializedString); } catch (Exception $exception) { throw UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $exception); } } /** * @template T of object * @phpstan-param ReflectionClass $reflectionClass */ private function isInstantiableViaReflection(ReflectionClass $reflectionClass): bool { return ! ($this->hasInternalAncestors($reflectionClass) && $reflectionClass->isFinal()); } /** * Verifies whether the given class is to be considered internal * * @template T of object * @phpstan-param ReflectionClass $reflectionClass */ private function hasInternalAncestors(ReflectionClass $reflectionClass): bool { do { if ($reflectionClass->isInternal()) { return true; } $reflectionClass = $reflectionClass->getParentClass(); } while ($reflectionClass); return false; } /** * Checks if a class is cloneable * * Classes implementing `__clone` cannot be safely cloned, as that may cause side-effects. * * @template T of object * @phpstan-param ReflectionClass $reflectionClass */ private function isSafeToClone(ReflectionClass $reflectionClass): bool { return $reflectionClass->isCloneable() && ! $reflectionClass->hasMethod('__clone') && ! $reflectionClass->isSubclassOf(ArrayIterator::class); } } src/Doctrine/Instantiator/InstantiatorInterface.php000064400000000744144760122170016603 0ustar00 $className */ public function instantiate($className); }