Completed
Pull Request — 2.x (#158)
by Akihito
09:50 queued 07:31
created

CachedCompiler::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Aop;
6
7
use Doctrine\Common\Annotations\AnnotationException;
8
use Doctrine\Common\Cache\Cache;
9
use ReflectionClass;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Ray\Aop\ReflectionClass.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
10
11
use function fileatime;
12
13
final class CachedCompiler implements CompilerInterface
14
{
15
    /** @var Compiler */
16
    private $compiler;
17
18
    /** @var Cache */
19
    private $cache;
20
21
    /**
22
     * @throws AnnotationException
23
     */
24
    public function __construct(string $classDir, Cache $cache)
25
    {
26
        $this->compiler = new Compiler($classDir);
27
        $this->cache = $cache;
28
    }
29
30
    /**
31
     * {@inheritdoc}
32
     */
33
    public function newInstance(string $class, array $args, BindInterface $bind)
34
    {
35
        $compiledClass = $this->compile($class, $bind);
36
        $instance = (new ReflectionClass($compiledClass))->newInstanceArgs($args);
37
        if (isset($instance->bindings)) {
38
            $instance->bindings = $bind->getBindings();
39
        }
40
41
        return $instance;
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function compile(string $class, BindInterface $bind): string
48
    {
49
        $classPath = (string) (new ReflectionClass($class))->getFileName();
50
        $id = $bind->toString('') . fileatime($classPath) . $class;
51
        /** @var ?CachedClass $cachedClass */
0 ignored issues
show
Documentation introduced by
The doc-type ?CachedClass could not be parsed: Unknown type name "?CachedClass" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
52
        $cachedClass = $this->cache->fetch($id);
53
        if ($cachedClass instanceof CachedClass && $cachedClass->require()) {
54
            return $cachedClass->class;
55
        }
56
57
        $compiledName = $this->compiler->compile($class, $bind);
58
        $compiledPath = (string) (new ReflectionClass($compiledName))->getFileName();
59
        $this->cache->save($id, new CachedClass($compiledName, $compiledPath));
60
61
        return $compiledName;
62
    }
63
}
64