Full Code of doctrine/instantiator for AI

2.1.x eede1167376e cached
46 files
44.1 KB
11.7k tokens
76 symbols
1 requests
Download .txt
Repository: doctrine/instantiator
Branch: 2.1.x
Commit: eede1167376e
Files: 46
Total size: 44.1 KB

Directory structure:
gitextract_gga815b3/

├── .doctrine-project.json
├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── coding-standards.yml
│       ├── continuous-integration.yml
│       ├── phpbench.yml
│       ├── release-on-milestone-closed.yml
│       ├── static-analysis.yml
│       └── website-schema.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── composer.json
├── docs/
│   └── en/
│       ├── index.rst
│       └── sidebar.rst
├── phpbench.json
├── phpcs.xml.dist
├── phpmd.xml.dist
├── phpstan.neon.dist
├── phpunit.xml.dist
├── src/
│   ├── Exception/
│   │   ├── ExceptionInterface.php
│   │   ├── InvalidArgumentException.php
│   │   └── UnexpectedValueException.php
│   ├── Instantiator.php
│   └── InstantiatorInterface.php
└── tests/
    ├── InstantiatorPerformance/
    │   └── InstantiatorPerformanceBench.php
    ├── InstantiatorTest/
    │   ├── Exception/
    │   │   ├── InvalidArgumentExceptionTest.php
    │   │   └── UnexpectedValueExceptionTest.php
    │   └── InstantiatorTest.php
    └── InstantiatorTestAsset/
        ├── AbstractClassAsset.php
        ├── ArrayObjectAsset.php
        ├── ExceptionAsset.php
        ├── FinalExceptionAsset.php
        ├── PharAsset.php
        ├── PharExceptionAsset.php
        ├── SerializableArrayObjectAsset.php
        ├── SerializableFinalInternalChildAsset.php
        ├── SimpleEnumAsset.php
        ├── SimpleSerializableAsset.php
        ├── SimpleTraitAsset.php
        ├── UnCloneableAsset.php
        ├── UnserializeExceptionArrayObjectAsset.php
        ├── WakeUpNoticesAsset.php
        └── XMLReaderAsset.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .doctrine-project.json
================================================
{
    "active": true,
    "name": "Instantiator",
    "slug": "instantiator",
    "docsSlug": "doctrine-instantiator",
    "versions": [
        {
            "name": "2.2",
            "branchName": "2.2.x",
            "slug": "2.2",
            "upcoming": true
        },
        {
            "name": "2.1",
            "branchName": "2.1.x",
            "slug": "2.1",
            "current": true
        },
        {
            "name": "2.0",
            "slug": "2.0",
            "maintained": false
        },
        {
            "name": "1.5",
            "slug": "1.5",
            "maintained": false
        },
        {
            "name": "1.4",
            "slug": "1.4",
            "maintained": false
        },
        {
            "name": "1.3",
            "slug": "1.3",
            "maintained": false
        }
    ]
}


================================================
FILE: .gitattributes
================================================
/.github               export-ignore
/tests                 export-ignore
/docs                  export-ignore
.doctrine-project.json export-ignore
.gitattributes         export-ignore
.gitignore             export-ignore
phpbench.json          export-ignore
phpcs.xml.dist         export-ignore
phpmd.xml.dist         export-ignore
phpstan.neon.dist      export-ignore
phpunit.xml.dist       export-ignore
composer.lock          export-ignore
/CONTRIBUTING.md       export-ignore


================================================
FILE: .github/FUNDING.yml
================================================
patreon: phpdoctrine
tidelift: packagist/doctrine%2Finstantiator
custom: https://www.doctrine-project.org/sponsorship.html


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    labels:
      - "CI"


================================================
FILE: .github/workflows/coding-standards.yml
================================================

name: "Coding Standards"

on:
  pull_request:
    branches:
      - "*.x"
  push:
    branches:
      - "*.x"

jobs:
  coding-standards:
    name: "Coding Standards"
    uses: "doctrine/.github/.github/workflows/coding-standards.yml@14.0.0"


================================================
FILE: .github/workflows/continuous-integration.yml
================================================

name: "Continuous Integration"

on:
  pull_request:
    branches:
      - "*.x"
  push:
    branches:
      - "*.x"

jobs:
  phpunit:
    name: "PHPUnit"
    uses: "doctrine/.github/.github/workflows/continuous-integration.yml@14.0.0"
    with:
      php-versions: '["8.4", "8.5"]'
    secrets:
      CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"


================================================
FILE: .github/workflows/phpbench.yml
================================================

name: "Performance benchmark"

on:
  pull_request:
    branches:
      - "*.x"
  push:
    branches:
      - "*.x"

env:
  fail-fast: true

jobs:
  phpbench:
    name: "PHPBench"
    runs-on: "ubuntu-22.04"

    strategy:
      matrix:
        php-version:
          - "8.4"
          - "8.5"

    steps:
      - name: "Checkout"
        uses: "actions/checkout@v6"
        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: "Install dependencies with Composer"
        uses: "ramsey/composer-install@v4"

      - name: "Run PHPBench"
        run: "php ./vendor/bin/phpbench run --iterations=3 --warmup=1 --report=aggregate"


================================================
FILE: .github/workflows/release-on-milestone-closed.yml
================================================
name: "Automatic Releases"

on:
  milestone:
    types:
      - "closed"

jobs:
  release:
    name: "Git tag, release & create merge-up PR"
    uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@13.1.0"
    secrets:
      GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
      GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
      ORGANIZATION_ADMIN_TOKEN: ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
      SIGNING_SECRET_KEY: ${{ secrets.SIGNING_SECRET_KEY }}


================================================
FILE: .github/workflows/static-analysis.yml
================================================

name: "Static Analysis"

on:
  pull_request:
    branches:
      - "*.x"
  push:
    branches:
      - "*.x"

jobs:
  static-analysis:
    name: "Static Analysis"
    uses: "doctrine/.github/.github/workflows/phpstan.yml@14.0.0"


================================================
FILE: .github/workflows/website-schema.yml
================================================

name: "Website config validation"

on:
  pull_request:
    branches:
      - "*.x"
    paths:
      - ".doctrine-project.json"
      - ".github/workflows/website-schema.yml"
  push:
    branches:
      - "*.x"
    paths:
      - ".doctrine-project.json"
      - ".github/workflows/website-schema.yml"

jobs:
  json-validate:
    name: "Validate JSON schema"
    uses: "doctrine/.github/.github/workflows/website-schema.yml@14.0.0"


================================================
FILE: .gitignore
================================================
phpunit.xml
/.phpunit.cache
build
vendor
/composer.lock
coverage.clover
/phpcs.xml
/.phpcs-cache
/phpstan.neon


================================================
FILE: CONTRIBUTING.md
================================================
# 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.



================================================
FILE: LICENSE
================================================
Copyright (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.


================================================
FILE: README.md
================================================
# Doctrine 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
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:

```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.


================================================
FILE: composer.json
================================================
{
    "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": "^8.4"
    },
    "require-dev": {
        "ext-phar":                  "*",
        "ext-pdo":                   "*",
        "doctrine/coding-standard":  "^14",
        "phpbench/phpbench":         "^1.2",
        "phpstan/phpstan":           "^2.1",
        "phpstan/phpstan-phpunit":   "^2.0",
        "phpunit/phpunit":           "^10.5.58"
    },
    "autoload": {
        "psr-4": {
            "Doctrine\\Instantiator\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "DoctrineTest\\InstantiatorPerformance\\": "tests/InstantiatorPerformance",
            "DoctrineTest\\InstantiatorTest\\": "tests/InstantiatorTest",
            "DoctrineTest\\InstantiatorTestAsset\\": "tests/InstantiatorTestAsset"
        }
    },
    "config": {
        "allow-plugins": {
            "dealerdirect/phpcodesniffer-composer-installer": true
        }
    }
}


================================================
FILE: docs/en/index.rst
================================================
Introduction
============

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

    <?php

    use Doctrine\Instantiator\Instantiator;
    use App\Entities\User;

    $instantiator = new Instantiator();

    $user = $instantiator->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


================================================
FILE: docs/en/sidebar.rst
================================================
.. toctree::
    :depth: 3

    index


================================================
FILE: phpbench.json
================================================
{
    "runner.bootstrap": "vendor/autoload.php",
    "runner.path": "tests/InstantiatorPerformance"
}


================================================
FILE: phpcs.xml.dist
================================================
<?xml version="1.0"?>
<ruleset
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd"
>
    <arg name="basepath" value="."/>
    <arg name="extensions" value="php"/>
    <arg name="parallel" value="80"/>
    <arg name="cache" value=".phpcs-cache"/>
    <arg name="colors"/>

    <!-- Ignore warnings, show progress of the run and show sniff names -->
    <arg value="nps"/>

    <config name="php_version" value="80400"/>

    <file>src</file>
    <file>tests</file>

    <rule ref="Doctrine">
        <exclude name="SlevomatCodingStandard.Exceptions.ReferenceThrowableOnly.ReferencedGeneralException"/>
    </rule>

    <rule ref="SlevomatCodingStandard.Classes.SuperfluousAbstractClassNaming">
        <exclude-pattern>tests/InstantiatorTestAsset/AbstractClassAsset.php</exclude-pattern>
    </rule>

    <rule ref="SlevomatCodingStandard.Classes.SuperfluousExceptionNaming">
        <exclude-pattern>src/Exception/UnexpectedValueException.php</exclude-pattern>
        <exclude-pattern>src/Exception/InvalidArgumentException.php</exclude-pattern>
    </rule>

    <rule ref="SlevomatCodingStandard.Classes.SuperfluousInterfaceNaming">
        <exclude-pattern>src/Exception/ExceptionInterface.php</exclude-pattern>
        <exclude-pattern>src/InstantiatorInterface.php</exclude-pattern>
    </rule>
</ruleset>


================================================
FILE: phpmd.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8" ?>
<ruleset
    name="Instantiator rules"
    xmlns="http://pmd.sf.net/ruleset/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
    xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"
>
    <rule ref="rulesets/cleancode.xml">
        <!-- static access is used for caching purposes -->
        <exclude name="StaticAccess"/>
    </rule>
    <rule ref="rulesets/codesize.xml"/>
    <rule ref="rulesets/controversial.xml"/>
    <rule ref="rulesets/design.xml"/>
    <rule ref="rulesets/naming.xml"/>
    <rule ref="rulesets/unusedcode.xml"/>
    <rule
        name="NPathComplexity"
        message="The {0} {1}() has an NPath complexity of {2}. The configured NPath complexity threshold is {3}."
        class="PHP_PMD_Rule_Design_NpathComplexity"
    >
        <properties>
            <property name="minimum" description="The npath reporting threshold" value="10"/>
        </properties>
    </rule>
</ruleset>


================================================
FILE: phpstan.neon.dist
================================================
includes:
    - vendor/phpstan/phpstan-phpunit/extension.neon
    - vendor/phpstan/phpstan-phpunit/rules.neon

parameters:
    level: max
    phpVersion: 80400
    paths:
        - src
        - tests

    ignoreErrors:
        # PHPStan is unable to infer the return type of unserialize() in this case.
        -
            message: '#Method Doctrine\\Instantiator\\Instantiator\:\:buildFactory\(\) should return callable\(\): T but returns Closure\(\): mixed\.#'
            path: 'src/Instantiator.php'

        # dynamic properties confuse static analysis
        -
            message: '#Access to an undefined property object::\$foo\.#'
            path: 'tests/InstantiatorTest/InstantiatorTest.php'

	# The property is static, we cannot use templating here
        -
            message: '#instantiate\(\) should return#'
            path: 'src/Instantiator.php'

	# this trait is not meant to be use'd
        -
            message: '#is used zero times#'
            path: 'tests/InstantiatorTestAsset/SimpleTraitAsset.php'


================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
    bootstrap="./vendor/autoload.php"
    colors="true"
    stopOnFailure="false"
    processIsolation="false"
    backupGlobals="false"
    cacheDirectory=".phpunit.cache">
    <coverage includeUncoveredFiles="true"/>
    <php>
        <ini name="error_reporting" value="-1"/>
    </php>

    <testsuite name="Doctrine\Instantiator tests">
        <directory>./tests/InstantiatorTest</directory>
    </testsuite>
    <source>
        <include>
            <directory suffix=".php">./src</directory>
        </include>
    </source>
</phpunit>


================================================
FILE: src/Exception/ExceptionInterface.php
================================================
<?php

declare(strict_types=1);

namespace Doctrine\Instantiator\Exception;

use Throwable;

/**
 * Base exception marker interface for the instantiator component
 */
interface ExceptionInterface extends Throwable
{
}


================================================
FILE: src/Exception/InvalidArgumentException.php
================================================
<?php

declare(strict_types=1);

namespace Doctrine\Instantiator\Exception;

use InvalidArgumentException as BaseInvalidArgumentException;
use ReflectionClass;

use function interface_exists;
use function sprintf;
use function trait_exists;

/**
 * Exception for invalid arguments provided to the instantiator
 */
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 cannot be instantiated', $className));
        }

        if (trait_exists($className)) {
            return new self(sprintf('The provided type "%s" is a trait, and cannot be instantiated', $className));
        }

        return new self(sprintf('The provided class "%s" does not exist', $className));
    }

    /**
     * @phpstan-param ReflectionClass<T> $reflectionClass
     *
     * @template T of object
     */
    public static function fromAbstractClass(ReflectionClass $reflectionClass): self
    {
        return new self(sprintf(
            'The provided class "%s" is abstract, and cannot be instantiated',
            $reflectionClass->getName(),
        ));
    }

    public static function fromEnum(string $className): self
    {
        return new self(sprintf(
            'The provided class "%s" is an enum, and cannot be instantiated',
            $className,
        ));
    }
}


================================================
FILE: src/Exception/UnexpectedValueException.php
================================================
<?php

declare(strict_types=1);

namespace Doctrine\Instantiator\Exception;

use Exception;
use ReflectionClass;
use UnexpectedValueException as BaseUnexpectedValueException;

use function sprintf;

/**
 * Exception for given parameters causing invalid/unexpected state on instantiation
 */
class UnexpectedValueException extends BaseUnexpectedValueException implements ExceptionInterface
{
    /**
     * @phpstan-param ReflectionClass<T> $reflectionClass
     *
     * @template T of object
     */
    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,
        );
    }

    /**
     * @phpstan-param ReflectionClass<T> $reflectionClass
     *
     * @template T of object
     */
    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),
        );
    }
}


================================================
FILE: src/Instantiator.php
================================================
<?php

declare(strict_types=1);

namespace Doctrine\Instantiator;

use ArrayIterator;
use Doctrine\Instantiator\Exception\ExceptionInterface;
use Doctrine\Instantiator\Exception\InvalidArgumentException;
use Doctrine\Instantiator\Exception\UnexpectedValueException;
use Exception;
use ReflectionClass;
use ReflectionException;
use Serializable;

use function class_exists;
use function enum_exists;
use function is_subclass_of;
use function restore_error_handler;
use function set_error_handler;
use function sprintf;
use function strlen;
use function unserialize;

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.
     */
    private const string SERIALIZATION_FORMAT_USE_UNSERIALIZER   = 'C';
    private const string SERIALIZATION_FORMAT_AVOID_UNSERIALIZER = 'O';

    /**
     * Used to instantiate specific classes, indexed by class name.
     *
     * @var array<class-string, callable(): object>
     */
    private static array $cachedInstantiators = [];

    /**
     * Array of objects that can directly be cloned, indexed by class name.
     *
     * @var object[]
     */
    private static array $cachedCloneables = [];

    /**
     * @phpstan-param class-string<T> $className
     *
     * @phpstan-return T
     *
     * @throws ExceptionInterface
     *
     * @template T of object
     */
    public function instantiate(string $className): object
    {
        if (isset(self::$cachedCloneables[$className])) {
            /** @phpstan-var T */
            $cachedCloneable = self::$cachedCloneables[$className];

            return clone $cachedCloneable;
        }

        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
     *
     * @phpstan-param class-string<T> $className
     *
     * @phpstan-return T
     *
     * @template T of object
     */
    private function buildAndCacheFromFactory(string $className): object
    {
        $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.
     *
     * @phpstan-param class-string<T> $className
     *
     * @phpstan-return callable(): T
     *
     * @throws InvalidArgumentException
     * @throws UnexpectedValueException
     * @throws ReflectionException
     *
     * @template T of object
     */
    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 fn () => unserialize($serializedString);
    }

    /**
     * @phpstan-param class-string<T> $className
     *
     * @phpstan-return ReflectionClass<T>
     *
     * @throws InvalidArgumentException
     * @throws ReflectionException
     *
     * @template T of object
     */
    private function getReflectionClass(string $className): ReflectionClass
    {
        if (! class_exists($className)) {
            throw InvalidArgumentException::fromNonExistingClass($className);
        }

        if (enum_exists($className, false)) {
            throw InvalidArgumentException::fromEnum($className);
        }

        $reflection = new ReflectionClass($className);

        if ($reflection->isAbstract()) {
            throw InvalidArgumentException::fromAbstractClass($reflection);
        }

        return $reflection;
    }

    /**
     * @phpstan-param ReflectionClass<T> $reflectionClass
     *
     * @throws UnexpectedValueException
     *
     * @template T of object
     */
    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;
        }
    }

    /**
     * @phpstan-param ReflectionClass<T> $reflectionClass
     *
     * @throws UnexpectedValueException
     *
     * @template T of object
     */
    private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, string $serializedString): void
    {
        try {
            unserialize($serializedString);
        } catch (Exception $exception) {
            throw UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $exception);
        }
    }

    /**
     * @phpstan-param ReflectionClass<T> $reflectionClass
     *
     * @template T of object
     */
    private function isInstantiableViaReflection(ReflectionClass $reflectionClass): bool
    {
        return ! ($this->hasInternalAncestors($reflectionClass) && $reflectionClass->isFinal());
    }

    /**
     * Verifies whether the given class is to be considered internal
     *
     * @phpstan-param ReflectionClass<T> $reflectionClass
     *
     * @template T of object
     */
    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.
     *
     * @phpstan-param ReflectionClass<T> $reflectionClass
     *
     * @template T of object
     */
    private function isSafeToClone(ReflectionClass $reflectionClass): bool
    {
        return $reflectionClass->isCloneable()
            && ! $reflectionClass->hasMethod('__clone')
            && ! $reflectionClass->isSubclassOf(ArrayIterator::class);
    }
}


================================================
FILE: src/InstantiatorInterface.php
================================================
<?php

declare(strict_types=1);

namespace Doctrine\Instantiator;

use Doctrine\Instantiator\Exception\ExceptionInterface;

/**
 * Instantiator provides utility methods to build objects without invoking their constructors
 */
interface InstantiatorInterface
{
    /**
     * @phpstan-param class-string<T> $className
     *
     * @phpstan-return T
     *
     * @throws ExceptionInterface
     *
     * @template T of object
     */
    public function instantiate(string $className): object;
}


================================================
FILE: tests/InstantiatorPerformance/InstantiatorPerformanceBench.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorPerformance;

use ArrayObject;
use Doctrine\Instantiator\Instantiator;
use DoctrineTest\InstantiatorTestAsset\SerializableArrayObjectAsset;
use DoctrineTest\InstantiatorTestAsset\SimpleSerializableAsset;
use DoctrineTest\InstantiatorTestAsset\UnCloneableAsset;
use PhpBench\Benchmark\Metadata\Annotations\BeforeMethods;
use PhpBench\Benchmark\Metadata\Annotations\Revs;

/**
 * Performance tests for {@see \Doctrine\Instantiator\Instantiator}
 *
 * @BeforeMethods({"init"})
 */
class InstantiatorPerformanceBench
{
    private Instantiator $instantiator;

    public function init(): void
    {
        $this->instantiator = new Instantiator();

        $this->instantiator->instantiate(self::class);
        $this->instantiator->instantiate(ArrayObject::class);
        $this->instantiator->instantiate(SimpleSerializableAsset::class);
        $this->instantiator->instantiate(SerializableArrayObjectAsset::class);
        $this->instantiator->instantiate(UnCloneableAsset::class);
    }

    /** @Revs(20000) */
    public function benchInstantiateSelf(): void
    {
        $this->instantiator->instantiate(self::class);
    }

    /** @Revs(20000) */
    public function benchInstantiateInternalClass(): void
    {
        $this->instantiator->instantiate(ArrayObject::class);
    }

    /** @Revs(20000) */
    public function benchInstantiateSimpleSerializableAssetClass(): void
    {
        $this->instantiator->instantiate(SimpleSerializableAsset::class);
    }

    /** @Revs(20000) */
    public function benchInstantiateSerializableArrayObjectAsset(): void
    {
        $this->instantiator->instantiate(SerializableArrayObjectAsset::class);
    }

    /** @Revs(20000) */
    public function benchInstantiateUnCloneableAsset(): void
    {
        $this->instantiator->instantiate(UnCloneableAsset::class);
    }
}


================================================
FILE: tests/InstantiatorTest/Exception/InvalidArgumentExceptionTest.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTest\Exception;

use Doctrine\Instantiator\Exception\InvalidArgumentException;
use Doctrine\Instantiator\InstantiatorInterface;
use DoctrineTest\InstantiatorTestAsset\AbstractClassAsset;
use DoctrineTest\InstantiatorTestAsset\SimpleTraitAsset;
use PHPUnit\Framework\TestCase;
use ReflectionClass;

use function sprintf;
use function str_replace;
use function uniqid;

/**
 * Tests for {@see \Doctrine\Instantiator\Exception\InvalidArgumentException}
 *
 * @covers \Doctrine\Instantiator\Exception\InvalidArgumentException
 */
class InvalidArgumentExceptionTest extends TestCase
{
    public function testFromNonExistingTypeWithNonExistingClass(): void
    {
        $className = self::class . str_replace('.', '', uniqid('', true));
        $exception = InvalidArgumentException::fromNonExistingClass($className);

        self::assertSame('The provided class "' . $className . '" does not exist', $exception->getMessage());
    }

    public function testFromNonExistingTypeWithTrait(): void
    {
        $exception = InvalidArgumentException::fromNonExistingClass(SimpleTraitAsset::class);

        self::assertSame(
            sprintf('The provided type "%s" is a trait, and cannot be instantiated', SimpleTraitAsset::class),
            $exception->getMessage(),
        );
    }

    public function testFromNonExistingTypeWithInterface(): void
    {
        $exception = InvalidArgumentException::fromNonExistingClass(InstantiatorInterface::class);

        self::assertSame(
            sprintf(
                'The provided type "%s" is an interface, and cannot be instantiated',
                InstantiatorInterface::class,
            ),
            $exception->getMessage(),
        );
    }

    public function testFromAbstractClass(): void
    {
        $reflection = new ReflectionClass(AbstractClassAsset::class);
        $exception  = InvalidArgumentException::fromAbstractClass($reflection);

        self::assertSame(
            sprintf(
                'The provided class "%s" is abstract, and cannot be instantiated',
                AbstractClassAsset::class,
            ),
            $exception->getMessage(),
        );
    }
}


================================================
FILE: tests/InstantiatorTest/Exception/UnexpectedValueExceptionTest.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTest\Exception;

use Doctrine\Instantiator\Exception\UnexpectedValueException;
use DoctrineTest\InstantiatorTestAsset\AbstractClassAsset;
use Exception;
use PHPUnit\Framework\TestCase;
use ReflectionClass;

use function sprintf;

/**
 * Tests for {@see \Doctrine\Instantiator\Exception\UnexpectedValueException}
 *
 * @covers \Doctrine\Instantiator\Exception\UnexpectedValueException
 */
class UnexpectedValueExceptionTest extends TestCase
{
    public function testFromSerializationTriggeredException(): void
    {
        $reflectionClass = new ReflectionClass($this);
        $previous        = new Exception();
        $exception       = UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $previous);

        self::assertSame($previous, $exception->getPrevious());
        self::assertSame(
            'An exception was raised while trying to instantiate an instance of "'
            . self::class . '" via un-serialization',
            $exception->getMessage(),
        );
    }

    public function testFromUncleanUnSerialization(): void
    {
        $reflection = new ReflectionClass(AbstractClassAsset::class);
        $exception  = UnexpectedValueException::fromUncleanUnSerialization($reflection, 'foo', 123, 'bar', 456);

        self::assertSame(
            sprintf(
                'Could not produce an instance of "%s" '
                . 'via un-serialization, since an error was triggered in file "bar" at line "456"',
                AbstractClassAsset::class,
            ),
            $exception->getMessage(),
        );

        $previous = $exception->getPrevious();

        self::assertInstanceOf(Exception::class, $previous);
        self::assertSame('foo', $previous->getMessage());
        self::assertSame(123, $previous->getCode());
    }
}


================================================
FILE: tests/InstantiatorTest/InstantiatorTest.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTest;

use ArrayObject;
use Doctrine\Instantiator\Exception\InvalidArgumentException;
use Doctrine\Instantiator\Exception\UnexpectedValueException;
use Doctrine\Instantiator\Instantiator;
use Doctrine\Instantiator\InstantiatorInterface;
use DoctrineTest\InstantiatorTestAsset\AbstractClassAsset;
use DoctrineTest\InstantiatorTestAsset\ArrayObjectAsset;
use DoctrineTest\InstantiatorTestAsset\ExceptionAsset;
use DoctrineTest\InstantiatorTestAsset\FinalExceptionAsset;
use DoctrineTest\InstantiatorTestAsset\PharExceptionAsset;
use DoctrineTest\InstantiatorTestAsset\SerializableArrayObjectAsset;
use DoctrineTest\InstantiatorTestAsset\SerializableFinalInternalChildAsset;
use DoctrineTest\InstantiatorTestAsset\SimpleEnumAsset;
use DoctrineTest\InstantiatorTestAsset\SimpleSerializableAsset;
use DoctrineTest\InstantiatorTestAsset\SimpleTraitAsset;
use DoctrineTest\InstantiatorTestAsset\UnCloneableAsset;
use DoctrineTest\InstantiatorTestAsset\UnserializeExceptionArrayObjectAsset;
use DoctrineTest\InstantiatorTestAsset\WakeUpNoticesAsset;
use DoctrineTest\InstantiatorTestAsset\XMLReaderAsset;
use Exception;
use Generator;
use PDORow;
use PharException;
use PHPUnit\Framework\TestCase;
use stdClass;

use function str_replace;
use function uniqid;

/**
 * Tests for {@see \Doctrine\Instantiator\Instantiator}
 *
 * @covers \Doctrine\Instantiator\Instantiator
 */
class InstantiatorTest extends TestCase
{
    private Instantiator $instantiator;

    protected function setUp(): void
    {
        parent::setUp();

        $this->instantiator = new Instantiator();
    }

    /**
     * @phpstan-param class-string $className
     *
     * @dataProvider getInstantiableClasses
     */
    public function testCanInstantiate(string $className): void
    {
        self::assertInstanceOf($className, $this->instantiator->instantiate($className));
    }

    /**
     * @phpstan-param class-string $className
     *
     * @dataProvider getInstantiableClasses
     */
    public function testInstantiatesSeparateInstances(string $className): void
    {
        $instance1 = $this->instantiator->instantiate($className);
        $instance2 = $this->instantiator->instantiate($className);

        self::assertEquals($instance1, $instance2);
        self::assertNotSame($instance1, $instance2);
    }

    public function testExceptionOnUnSerializationException(): void
    {
        $this->expectException(UnexpectedValueException::class);

        $this->instantiator->instantiate(PDORow::class);
    }

    /**
     * @phpstan-param class-string $invalidClassName
     *
     * @dataProvider getInvalidClassNames
     */
    public function testInstantiationFromNonExistingClass(string $invalidClassName): void
    {
        $this->expectException(InvalidArgumentException::class);

        $this->instantiator->instantiate($invalidClassName);
    }

    public function testInstancesAreNotCloned(): void
    {
        $namespace = __NAMESPACE__;
        $className = 'TemporaryClass' . str_replace('.', '', uniqid('', true));

        eval(<<< PHP
namespace $namespace;
#[\AllowDynamicProperties]
class $className {}
PHP
        );

        /** @phpstan-var class-string */
        $classNameWithNamespace = $namespace . '\\' . $className;

        $instance = $this->instantiator->instantiate($classNameWithNamespace);

        $instance->foo = 'bar';

        $instance2 = $this->instantiator->instantiate($classNameWithNamespace);

        self::assertObjectNotHasProperty('foo', $instance2);
    }

    /**
     * Provides a list of instantiable classes (existing)
     *
     * @return string[][]
     * @phpstan-return list<array{class-string}>
     */
    public static function getInstantiableClasses(): array
    {
        return [
            [stdClass::class],
            [self::class],
            [Instantiator::class],
            [Exception::class],
            [PharException::class],
            [SimpleSerializableAsset::class],
            [ExceptionAsset::class],
            [FinalExceptionAsset::class],
            [PharExceptionAsset::class],
            [UnCloneableAsset::class],
            [XMLReaderAsset::class],
            [PharException::class],
            [ArrayObject::class],
            [ArrayObjectAsset::class],
            [SerializableArrayObjectAsset::class],
            [WakeUpNoticesAsset::class],
            [UnserializeExceptionArrayObjectAsset::class],
            [SerializableFinalInternalChildAsset::class],
        ];
    }

    /**
     * Provides a list of instantiable classes (existing)
     *
     * @return Generator<string, array{string}>
     */
    public static function getInvalidClassNames(): Generator
    {
        yield 'invalid string' => [self::class . str_replace('.', '', uniqid('', true))];
        yield 'interface' => [InstantiatorInterface::class];
        yield 'abstract class' => [AbstractClassAsset::class];
        yield 'trait' => [SimpleTraitAsset::class];
        yield 'enum' => [SimpleEnumAsset::class];
    }
}


================================================
FILE: tests/InstantiatorTestAsset/AbstractClassAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

/**
 * A simple asset for an abstract class
 */
abstract class AbstractClassAsset
{
}


================================================
FILE: tests/InstantiatorTestAsset/ArrayObjectAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use ArrayObject;
use BadMethodCallException;

/**
 * Test asset that extends an internal PHP class
 *
 * @template TValue
 * @template-extends ArrayObject<int, TValue>
 */
class ArrayObjectAsset extends ArrayObject
{
    /**
     * Constructor - should not be called
     *
     * @throws BadMethodCallException
     */
    public function __construct()
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }
}


================================================
FILE: tests/InstantiatorTestAsset/ExceptionAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use BadMethodCallException;
use Exception;

/**
 * Test asset that extends an internal PHP base exception
 */
class ExceptionAsset extends Exception
{
    /**
     * Constructor - should not be called
     *
     * @throws BadMethodCallException
     */
    public function __construct()
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }
}


================================================
FILE: tests/InstantiatorTestAsset/FinalExceptionAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use BadMethodCallException;
use Exception;

/**
 * Test asset that extends an internal PHP base exception
 */
final class FinalExceptionAsset extends Exception
{
    /**
     * Constructor - should not be called
     *
     * @throws BadMethodCallException
     */
    public function __construct()
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }
}


================================================
FILE: tests/InstantiatorTestAsset/PharAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use BadMethodCallException;
use Phar;

/**
 * Test asset that extends an internal PHP class
 */
class PharAsset extends Phar
{
    /**
     * Constructor - should not be called
     *
     * @throws BadMethodCallException
     */
    public function __construct()
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }
}


================================================
FILE: tests/InstantiatorTestAsset/PharExceptionAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use BadMethodCallException;
use PharException;

/**
 * Test asset that extends an internal PHP class
 * This class should be serializable without problems
 * and without getting the "Erroneous data format for unserializing"
 * error
 */
class PharExceptionAsset extends PharException
{
    /**
     * Constructor - should not be called
     *
     * @throws BadMethodCallException
     */
    public function __construct()
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }
}


================================================
FILE: tests/InstantiatorTestAsset/SerializableArrayObjectAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use ArrayObject;
use BadMethodCallException;
use Serializable;

/**
 * Serializable test asset that also extends an internal class
 *
 * @template TValue
 * @template-extends ArrayObject<int, TValue>
 */
class SerializableArrayObjectAsset extends ArrayObject implements Serializable
{
    /**
     * Constructor - should not be called
     *
     * @throws BadMethodCallException
     */
    public function __construct()
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }

    /**
     * {@inheritDoc}
     *
     * Should not be called
     *
     * @throws BadMethodCallException
     */
    public function unserialize($serialized): void
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }

    /** @param mixed[] $data */
    public function __unserialize(array $data): void
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }
}


================================================
FILE: tests/InstantiatorTestAsset/SerializableFinalInternalChildAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use ArrayIterator;

/**
 * @template TValue
 * @template-extends ArrayIterator<int, TValue>
 */
final class SerializableFinalInternalChildAsset extends ArrayIterator
{
}


================================================
FILE: tests/InstantiatorTestAsset/SimpleEnumAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

enum SimpleEnumAsset
{
    case Foo;
    case Bar;
}


================================================
FILE: tests/InstantiatorTestAsset/SimpleSerializableAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use BadMethodCallException;
use Serializable;

/**
 * Base serializable test asset
 */
class SimpleSerializableAsset implements Serializable
{
    /**
     * Constructor - should not be called
     *
     * @throws BadMethodCallException
     */
    public function __construct()
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }

    public function serialize(): string
    {
        return '';
    }

    /**
     * {@inheritDoc}
     *
     * Should not be called
     *
     * @throws BadMethodCallException
     */
    public function unserialize(string $serialized): void
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }

    /** @return mixed[] */
    public function __serialize(): array
    {
        return [];
    }

    /** @param mixed[] $data */
    public function __unserialize(array $data): void
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }
}


================================================
FILE: tests/InstantiatorTestAsset/SimpleTraitAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

/**
 * A simple trait with no attached logic
 */
trait SimpleTraitAsset
{
}


================================================
FILE: tests/InstantiatorTestAsset/UnCloneableAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use BadMethodCallException;

/**
 * Base un-cloneable asset
 */
class UnCloneableAsset
{
    /**
     * Constructor - should not be called
     *
     * @throws BadMethodCallException
     */
    public function __construct()
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }

    /**
     * Magic `__clone` - should not be invoked
     *
     * @throws BadMethodCallException
     */
    public function __clone()
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }
}


================================================
FILE: tests/InstantiatorTestAsset/UnserializeExceptionArrayObjectAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use ArrayObject;
use BadMethodCallException;

/**
 * A simple asset for an abstract class
 *
 * @template TValue
 * @template-extends ArrayObject<int, TValue>
 */
class UnserializeExceptionArrayObjectAsset extends ArrayObject
{
    /**
     * {@inheritDoc}
     */
    public function __wakeup()
    {
        throw new BadMethodCallException();
    }
}


================================================
FILE: tests/InstantiatorTestAsset/WakeUpNoticesAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use ArrayObject;

use function trigger_error;

/**
 * A simple asset for an abstract class
 *
 * @template TValue
 * @template-extends ArrayObject<int, TValue>
 */
class WakeUpNoticesAsset extends ArrayObject
{
    /**
     * Wakeup method called after un-serialization
     */
    public function __wakeup(): void
    {
        trigger_error('Something went bananas while un-serializing this instance');
    }
}


================================================
FILE: tests/InstantiatorTestAsset/XMLReaderAsset.php
================================================
<?php

declare(strict_types=1);

namespace DoctrineTest\InstantiatorTestAsset;

use BadMethodCallException;
use XMLReader;

/**
 * Test asset that extends an internal PHP class
 */
class XMLReaderAsset extends XMLReader
{
    /**
     * Constructor - should not be called
     *
     * @throws BadMethodCallException
     */
    public function __construct()
    {
        throw new BadMethodCallException('Not supposed to be called!');
    }
}
Download .txt
gitextract_gga815b3/

├── .doctrine-project.json
├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── dependabot.yml
│   └── workflows/
│       ├── coding-standards.yml
│       ├── continuous-integration.yml
│       ├── phpbench.yml
│       ├── release-on-milestone-closed.yml
│       ├── static-analysis.yml
│       └── website-schema.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── composer.json
├── docs/
│   └── en/
│       ├── index.rst
│       └── sidebar.rst
├── phpbench.json
├── phpcs.xml.dist
├── phpmd.xml.dist
├── phpstan.neon.dist
├── phpunit.xml.dist
├── src/
│   ├── Exception/
│   │   ├── ExceptionInterface.php
│   │   ├── InvalidArgumentException.php
│   │   └── UnexpectedValueException.php
│   ├── Instantiator.php
│   └── InstantiatorInterface.php
└── tests/
    ├── InstantiatorPerformance/
    │   └── InstantiatorPerformanceBench.php
    ├── InstantiatorTest/
    │   ├── Exception/
    │   │   ├── InvalidArgumentExceptionTest.php
    │   │   └── UnexpectedValueExceptionTest.php
    │   └── InstantiatorTest.php
    └── InstantiatorTestAsset/
        ├── AbstractClassAsset.php
        ├── ArrayObjectAsset.php
        ├── ExceptionAsset.php
        ├── FinalExceptionAsset.php
        ├── PharAsset.php
        ├── PharExceptionAsset.php
        ├── SerializableArrayObjectAsset.php
        ├── SerializableFinalInternalChildAsset.php
        ├── SimpleEnumAsset.php
        ├── SimpleSerializableAsset.php
        ├── SimpleTraitAsset.php
        ├── UnCloneableAsset.php
        ├── UnserializeExceptionArrayObjectAsset.php
        ├── WakeUpNoticesAsset.php
        └── XMLReaderAsset.php
Download .txt
SYMBOL INDEX (76 symbols across 23 files)

FILE: src/Exception/ExceptionInterface.php
  type ExceptionInterface (line 12) | interface ExceptionInterface extends Throwable

FILE: src/Exception/InvalidArgumentException.php
  class InvalidArgumentException (line 17) | class InvalidArgumentException extends BaseInvalidArgumentException impl...
    method fromNonExistingClass (line 19) | public static function fromNonExistingClass(string $className): self
    method fromAbstractClass (line 37) | public static function fromAbstractClass(ReflectionClass $reflectionCl...
    method fromEnum (line 45) | public static function fromEnum(string $className): self

FILE: src/Exception/UnexpectedValueException.php
  class UnexpectedValueException (line 16) | class UnexpectedValueException extends BaseUnexpectedValueException impl...
    method fromSerializationTriggeredException (line 23) | public static function fromSerializationTriggeredException(
    method fromUncleanUnSerialization (line 42) | public static function fromUncleanUnSerialization(

FILE: src/Instantiator.php
  class Instantiator (line 25) | final class Instantiator implements InstantiatorInterface
    method instantiate (line 58) | public function instantiate(string $className): object
    method buildAndCacheFromFactory (line 85) | private function buildAndCacheFromFactory(string $className): object
    method buildFactory (line 111) | private function buildFactory(string $className): callable
    method getReflectionClass (line 141) | private function getReflectionClass(string $className): ReflectionClass
    method checkIfUnSerializationIsSupported (line 167) | private function checkIfUnSerializationIsSupported(ReflectionClass $re...
    method attemptInstantiationViaUnSerialization (line 199) | private function attemptInstantiationViaUnSerialization(ReflectionClas...
    method isInstantiableViaReflection (line 213) | private function isInstantiableViaReflection(ReflectionClass $reflecti...
    method hasInternalAncestors (line 225) | private function hasInternalAncestors(ReflectionClass $reflectionClass...
    method isSafeToClone (line 247) | private function isSafeToClone(ReflectionClass $reflectionClass): bool

FILE: src/InstantiatorInterface.php
  type InstantiatorInterface (line 12) | interface InstantiatorInterface
    method instantiate (line 23) | public function instantiate(string $className): object;

FILE: tests/InstantiatorPerformance/InstantiatorPerformanceBench.php
  class InstantiatorPerformanceBench (line 20) | class InstantiatorPerformanceBench
    method init (line 24) | public function init(): void
    method benchInstantiateSelf (line 36) | public function benchInstantiateSelf(): void
    method benchInstantiateInternalClass (line 42) | public function benchInstantiateInternalClass(): void
    method benchInstantiateSimpleSerializableAssetClass (line 48) | public function benchInstantiateSimpleSerializableAssetClass(): void
    method benchInstantiateSerializableArrayObjectAsset (line 54) | public function benchInstantiateSerializableArrayObjectAsset(): void
    method benchInstantiateUnCloneableAsset (line 60) | public function benchInstantiateUnCloneableAsset(): void

FILE: tests/InstantiatorTest/Exception/InvalidArgumentExceptionTest.php
  class InvalidArgumentExceptionTest (line 23) | class InvalidArgumentExceptionTest extends TestCase
    method testFromNonExistingTypeWithNonExistingClass (line 25) | public function testFromNonExistingTypeWithNonExistingClass(): void
    method testFromNonExistingTypeWithTrait (line 33) | public function testFromNonExistingTypeWithTrait(): void
    method testFromNonExistingTypeWithInterface (line 43) | public function testFromNonExistingTypeWithInterface(): void
    method testFromAbstractClass (line 56) | public function testFromAbstractClass(): void

FILE: tests/InstantiatorTest/Exception/UnexpectedValueExceptionTest.php
  class UnexpectedValueExceptionTest (line 20) | class UnexpectedValueExceptionTest extends TestCase
    method testFromSerializationTriggeredException (line 22) | public function testFromSerializationTriggeredException(): void
    method testFromUncleanUnSerialization (line 36) | public function testFromUncleanUnSerialization(): void

FILE: tests/InstantiatorTest/InstantiatorTest.php
  class InstantiatorTest (line 41) | class InstantiatorTest extends TestCase
    method setUp (line 45) | protected function setUp(): void
    method testCanInstantiate (line 57) | public function testCanInstantiate(string $className): void
    method testInstantiatesSeparateInstances (line 67) | public function testInstantiatesSeparateInstances(string $className): ...
    method testExceptionOnUnSerializationException (line 76) | public function testExceptionOnUnSerializationException(): void
    method testInstantiationFromNonExistingClass (line 88) | public function testInstantiationFromNonExistingClass(string $invalidC...
    method testInstancesAreNotCloned (line 95) | public function testInstancesAreNotCloned(): void
    method getInstantiableClasses (line 125) | public static function getInstantiableClasses(): array
    method getInvalidClassNames (line 154) | public static function getInvalidClassNames(): Generator

FILE: tests/InstantiatorTestAsset/AbstractClassAsset.php
  class AbstractClassAsset (line 10) | abstract class AbstractClassAsset

FILE: tests/InstantiatorTestAsset/ArrayObjectAsset.php
  class ArrayObjectAsset (line 16) | class ArrayObjectAsset extends ArrayObject
    method __construct (line 23) | public function __construct()

FILE: tests/InstantiatorTestAsset/ExceptionAsset.php
  class ExceptionAsset (line 13) | class ExceptionAsset extends Exception
    method __construct (line 20) | public function __construct()

FILE: tests/InstantiatorTestAsset/FinalExceptionAsset.php
  class FinalExceptionAsset (line 13) | final class FinalExceptionAsset extends Exception
    method __construct (line 20) | public function __construct()

FILE: tests/InstantiatorTestAsset/PharAsset.php
  class PharAsset (line 13) | class PharAsset extends Phar
    method __construct (line 20) | public function __construct()

FILE: tests/InstantiatorTestAsset/PharExceptionAsset.php
  class PharExceptionAsset (line 16) | class PharExceptionAsset extends PharException
    method __construct (line 23) | public function __construct()

FILE: tests/InstantiatorTestAsset/SerializableArrayObjectAsset.php
  class SerializableArrayObjectAsset (line 17) | class SerializableArrayObjectAsset extends ArrayObject implements Serial...
    method __construct (line 24) | public function __construct()
    method unserialize (line 36) | public function unserialize($serialized): void
    method __unserialize (line 42) | public function __unserialize(array $data): void

FILE: tests/InstantiatorTestAsset/SerializableFinalInternalChildAsset.php
  class SerializableFinalInternalChildAsset (line 13) | final class SerializableFinalInternalChildAsset extends ArrayIterator

FILE: tests/InstantiatorTestAsset/SimpleSerializableAsset.php
  class SimpleSerializableAsset (line 13) | class SimpleSerializableAsset implements Serializable
    method __construct (line 20) | public function __construct()
    method serialize (line 25) | public function serialize(): string
    method unserialize (line 37) | public function unserialize(string $serialized): void
    method __serialize (line 43) | public function __serialize(): array
    method __unserialize (line 49) | public function __unserialize(array $data): void

FILE: tests/InstantiatorTestAsset/SimpleTraitAsset.php
  type SimpleTraitAsset (line 10) | trait SimpleTraitAsset

FILE: tests/InstantiatorTestAsset/UnCloneableAsset.php
  class UnCloneableAsset (line 12) | class UnCloneableAsset
    method __construct (line 19) | public function __construct()
    method __clone (line 29) | public function __clone()

FILE: tests/InstantiatorTestAsset/UnserializeExceptionArrayObjectAsset.php
  class UnserializeExceptionArrayObjectAsset (line 16) | class UnserializeExceptionArrayObjectAsset extends ArrayObject
    method __wakeup (line 21) | public function __wakeup()

FILE: tests/InstantiatorTestAsset/WakeUpNoticesAsset.php
  class WakeUpNoticesAsset (line 17) | class WakeUpNoticesAsset extends ArrayObject
    method __wakeup (line 22) | public function __wakeup(): void

FILE: tests/InstantiatorTestAsset/XMLReaderAsset.php
  class XMLReaderAsset (line 13) | class XMLReaderAsset extends XMLReader
    method __construct (line 20) | public function __construct()
Condensed preview — 46 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (50K chars).
[
  {
    "path": ".doctrine-project.json",
    "chars": 849,
    "preview": "{\n    \"active\": true,\n    \"name\": \"Instantiator\",\n    \"slug\": \"instantiator\",\n    \"docsSlug\": \"doctrine-instantiator\",\n "
  },
  {
    "path": ".gitattributes",
    "chars": 481,
    "preview": "/.github               export-ignore\n/tests                 export-ignore\n/docs                  export-ignore\n.doctrine"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 123,
    "preview": "patreon: phpdoctrine\ntidelift: packagist/doctrine%2Finstantiator\ncustom: https://www.doctrine-project.org/sponsorship.ht"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 143,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n  "
  },
  {
    "path": ".github/workflows/coding-standards.yml",
    "chars": 242,
    "preview": "\nname: \"Coding Standards\"\n\non:\n  pull_request:\n    branches:\n      - \"*.x\"\n  push:\n    branches:\n      - \"*.x\"\n\njobs:\n  "
  },
  {
    "path": ".github/workflows/continuous-integration.yml",
    "chars": 348,
    "preview": "\nname: \"Continuous Integration\"\n\non:\n  pull_request:\n    branches:\n      - \"*.x\"\n  push:\n    branches:\n      - \"*.x\"\n\njo"
  },
  {
    "path": ".github/workflows/phpbench.yml",
    "chars": 826,
    "preview": "\nname: \"Performance benchmark\"\n\non:\n  pull_request:\n    branches:\n      - \"*.x\"\n  push:\n    branches:\n      - \"*.x\"\n\nenv"
  },
  {
    "path": ".github/workflows/release-on-milestone-closed.yml",
    "chars": 482,
    "preview": "name: \"Automatic Releases\"\n\non:\n  milestone:\n    types:\n      - \"closed\"\n\njobs:\n  release:\n    name: \"Git tag, release &"
  },
  {
    "path": ".github/workflows/static-analysis.yml",
    "chars": 230,
    "preview": "\nname: \"Static Analysis\"\n\non:\n  pull_request:\n    branches:\n      - \"*.x\"\n  push:\n    branches:\n      - \"*.x\"\n\njobs:\n  s"
  },
  {
    "path": ".github/workflows/website-schema.yml",
    "chars": 432,
    "preview": "\nname: \"Website config validation\"\n\non:\n  pull_request:\n    branches:\n      - \"*.x\"\n    paths:\n      - \".doctrine-projec"
  },
  {
    "path": ".gitignore",
    "chars": 111,
    "preview": "phpunit.xml\n/.phpunit.cache\nbuild\nvendor\n/composer.lock\ncoverage.clover\n/phpcs.xml\n/.phpcs-cache\n/phpstan.neon\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1032,
    "preview": "# Contributing\n\n * Follow the [Doctrine Coding Standard](https://github.com/doctrine/coding-standard)\n * The project wil"
  },
  {
    "path": "LICENSE",
    "chars": 1060,
    "preview": "Copyright (c) 2014 Doctrine Project\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthi"
  },
  {
    "path": "README.md",
    "chars": 1588,
    "preview": "# Doctrine Instantiator\n\nThis library provides a way of avoiding usage of constructors when instantiating PHP classes.\n\n"
  },
  {
    "path": "composer.json",
    "chars": 1512,
    "preview": "{\n    \"name\":              \"doctrine/instantiator\",\n    \"description\":       \"A small, lightweight utility to instantiat"
  },
  {
    "path": "docs/en/index.rst",
    "chars": 1757,
    "preview": "Introduction\n============\n\nThis library provides a way of avoiding usage of constructors when instantiating PHP classes."
  },
  {
    "path": "docs/en/sidebar.rst",
    "chars": 38,
    "preview": ".. toctree::\n    :depth: 3\n\n    index\n"
  },
  {
    "path": "phpbench.json",
    "chars": 102,
    "preview": "{\n    \"runner.bootstrap\": \"vendor/autoload.php\",\n    \"runner.path\": \"tests/InstantiatorPerformance\"\n}\n"
  },
  {
    "path": "phpcs.xml.dist",
    "chars": 1404,
    "preview": "<?xml version=\"1.0\"?>\n<ruleset\n        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n        xsi:noNamespaceSche"
  },
  {
    "path": "phpmd.xml.dist",
    "chars": 1085,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<ruleset\n    name=\"Instantiator rules\"\n    xmlns=\"http://pmd.sf.net/ruleset/1.0."
  },
  {
    "path": "phpstan.neon.dist",
    "chars": 1035,
    "preview": "includes:\n    - vendor/phpstan/phpstan-phpunit/extension.neon\n    - vendor/phpstan/phpstan-phpunit/rules.neon\n\nparameter"
  },
  {
    "path": "phpunit.xml.dist",
    "chars": 700,
    "preview": "<?xml version=\"1.0\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:noNamespaceSchemaLocation=\""
  },
  {
    "path": "src/Exception/ExceptionInterface.php",
    "chars": 218,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Instantiator\\Exception;\n\nuse Throwable;\n\n/**\n * Base exception marke"
  },
  {
    "path": "src/Exception/InvalidArgumentException.php",
    "chars": 1524,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Instantiator\\Exception;\n\nuse InvalidArgumentException as BaseInvalid"
  },
  {
    "path": "src/Exception/UnexpectedValueException.php",
    "chars": 1655,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Instantiator\\Exception;\n\nuse Exception;\nuse ReflectionClass;\nuse Une"
  },
  {
    "path": "src/Instantiator.php",
    "chars": 7367,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Instantiator;\n\nuse ArrayIterator;\nuse Doctrine\\Instantiator\\Exceptio"
  },
  {
    "path": "src/InstantiatorInterface.php",
    "chars": 496,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Instantiator;\n\nuse Doctrine\\Instantiator\\Exception\\ExceptionInterfac"
  },
  {
    "path": "tests/InstantiatorPerformance/InstantiatorPerformanceBench.php",
    "chars": 1895,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorPerformance;\n\nuse ArrayObject;\nuse Doctrine\\Instanti"
  },
  {
    "path": "tests/InstantiatorTest/Exception/InvalidArgumentExceptionTest.php",
    "chars": 2228,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTest\\Exception;\n\nuse Doctrine\\Instantiator\\Exception"
  },
  {
    "path": "tests/InstantiatorTest/Exception/UnexpectedValueExceptionTest.php",
    "chars": 1875,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTest\\Exception;\n\nuse Doctrine\\Instantiator\\Exception"
  },
  {
    "path": "tests/InstantiatorTest/InstantiatorTest.php",
    "chars": 5071,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTest;\n\nuse ArrayObject;\nuse Doctrine\\Instantiator\\Ex"
  },
  {
    "path": "tests/InstantiatorTestAsset/AbstractClassAsset.php",
    "chars": 166,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\n/**\n * A simple asset for an abstract cl"
  },
  {
    "path": "tests/InstantiatorTestAsset/ArrayObjectAsset.php",
    "chars": 520,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse ArrayObject;\nuse BadMethodCallExcept"
  },
  {
    "path": "tests/InstantiatorTestAsset/ExceptionAsset.php",
    "chars": 454,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse BadMethodCallException;\nuse Exceptio"
  },
  {
    "path": "tests/InstantiatorTestAsset/FinalExceptionAsset.php",
    "chars": 465,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse BadMethodCallException;\nuse Exceptio"
  },
  {
    "path": "tests/InstantiatorTestAsset/PharAsset.php",
    "chars": 430,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse BadMethodCallException;\nuse Phar;\n\n/"
  },
  {
    "path": "tests/InstantiatorTestAsset/PharExceptionAsset.php",
    "chars": 589,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse BadMethodCallException;\nuse PharExce"
  },
  {
    "path": "tests/InstantiatorTestAsset/SerializableArrayObjectAsset.php",
    "chars": 1011,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse ArrayObject;\nuse BadMethodCallExcept"
  },
  {
    "path": "tests/InstantiatorTestAsset/SerializableFinalInternalChildAsset.php",
    "chars": 250,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse ArrayIterator;\n\n/**\n * @template TVa"
  },
  {
    "path": "tests/InstantiatorTestAsset/SimpleEnumAsset.php",
    "chars": 133,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nenum SimpleEnumAsset\n{\n    case Foo;\n   "
  },
  {
    "path": "tests/InstantiatorTestAsset/SimpleSerializableAsset.php",
    "chars": 1048,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse BadMethodCallException;\nuse Serializ"
  },
  {
    "path": "tests/InstantiatorTestAsset/SimpleTraitAsset.php",
    "chars": 156,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\n/**\n * A simple trait with no attached l"
  },
  {
    "path": "tests/InstantiatorTestAsset/UnCloneableAsset.php",
    "chars": 615,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse BadMethodCallException;\n\n/**\n * Base"
  },
  {
    "path": "tests/InstantiatorTestAsset/UnserializeExceptionArrayObjectAsset.php",
    "chars": 434,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse ArrayObject;\nuse BadMethodCallExcept"
  },
  {
    "path": "tests/InstantiatorTestAsset/WakeUpNoticesAsset.php",
    "chars": 493,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse ArrayObject;\n\nuse function trigger_e"
  },
  {
    "path": "tests/InstantiatorTestAsset/XMLReaderAsset.php",
    "chars": 445,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DoctrineTest\\InstantiatorTestAsset;\n\nuse BadMethodCallException;\nuse XMLReade"
  }
]

About this extraction

This page contains the full source code of the doctrine/instantiator GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 46 files (44.1 KB), approximately 11.7k tokens, and a symbol index with 76 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!