Completed
Pull Request — 2.x (#158)
by Akihito
01:38
created

CachedCompiler::newInstance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
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 Doctrine\Common\Cache\PhpFileCache;
10
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...
11
12
use function file_exists;
13
use function fileatime;
14
use function mkdir;
15
16
final class CachedCompiler implements CompilerInterface
17
{
18
    /** @var Compiler */
19
    private $compiler;
20
21
    /** @var Cache */
22
    private $cache;
23
24
    /**
25
     * @throws AnnotationException
26
     */
27
    public function __construct(string $classDir, ?Cache $cache = null)
28
    {
29
        $this->compiler = new Compiler($classDir);
30
        if ($cache === null) {
31
            $tmpDir = $classDir . '/aop_cache';
32
            if (! file_exists($tmpDir)) {
33
                mkdir($tmpDir);
34
            }
35
36
            $cache = new PhpFileCache($tmpDir);
37
        }
38
39
        $this->cache = $cache;
40
    }
41
42
    /**
43
     * {@inheritdoc}
44
     */
45
    public function newInstance(string $class, array $args, BindInterface $bind)
46
    {
47
        return $this->compiler->newInstance($class, $args, $bind);
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function compile(string $class, BindInterface $bind): string
54
    {
55
        $classPath = (string) (new ReflectionClass($class))->getFileName();
56
        $id = $bind->toString('') . fileatime($classPath);
57
        /** @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...
58
        $cachedClass = $this->cache->fetch($id);
59
        if ($cachedClass instanceof CachedClass && $cachedClass->require()) {
60
            return $cachedClass->class;
61
        }
62
63
        $compiledName = $this->compiler->compile($class, $bind);
64
        $compiledPath = (string) (new ReflectionClass($compiledName))->getFileName();
65
        $this->cache->save($id, new CachedClass($compiledName, $compiledPath));
66
67
        return $compiledName;
68
    }
69
}
70