Skip to content

Commit fdee566

Browse files
authored
Merge pull request #38 from goaop/fix/resolve-relative-paths
Resolve all relative paths to be compatible with original reflection. Closes #28, #31
2 parents 40032e3 + c90583a commit fdee566

6 files changed

+113
-1
lines changed

src/Instrument/PathResolver.php

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
/*
3+
* Go! AOP framework
4+
*
5+
* @copyright Copyright 2014, Lisachenko Alexander <[email protected]>
6+
*
7+
* This source file is subject to the license that is bundled
8+
* with this source code in the file LICENSE.
9+
*/
10+
11+
namespace Go\ParserReflection\Instrument;
12+
13+
/**
14+
* Special class for resolving path for different file systems, wrappers, etc
15+
*
16+
* @see http://stackoverflow.com/questions/4049856/replace-phps-realpath/4050444
17+
* @see http://bugs.php.net/bug.php?id=52769
18+
*
19+
* @link https://github.com/goaop/framework/blob/master/src/Instrument/PathResolver.php
20+
*/
21+
class PathResolver
22+
{
23+
24+
/**
25+
* Custom replacement for realpath() and stream_resolve_include_path()
26+
*
27+
* @param string|array $somePath Path without normalization or array of paths
28+
* @param bool $shouldCheckExistence Flag for checking existence of resolved filename
29+
*
30+
* @return array|bool|string
31+
*/
32+
public static function realpath($somePath, $shouldCheckExistence = false)
33+
{
34+
// Do not resolve empty string/false/arrays into the current path
35+
if (!$somePath) {
36+
return $somePath;
37+
}
38+
39+
if (is_array($somePath)) {
40+
return array_map(array(__CLASS__, __FUNCTION__), $somePath);
41+
}
42+
// Trick to get scheme name and path in one action. If no scheme, then there will be only one part
43+
$components = explode('://', $somePath, 2);
44+
list ($pathScheme, $path) = isset($components[1]) ? $components : array(null, $components[0]);
45+
46+
// Optimization to bypass complex logic for simple paths (eg. not in phar archives)
47+
if (!$pathScheme && ($fastPath = stream_resolve_include_path($somePath))) {
48+
return $fastPath;
49+
}
50+
51+
$isRelative = !$pathScheme && ($path[0] !== '/') && ($path[1] !== ':');
52+
if ($isRelative) {
53+
$path = getcwd() . DIRECTORY_SEPARATOR . $path;
54+
}
55+
56+
// resolve path parts (single dot, double dot and double delimiters)
57+
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
58+
if (strpos($path, '.') !== false) {
59+
$parts = explode(DIRECTORY_SEPARATOR, $path);
60+
$absolutes = [];
61+
foreach ($parts as $part) {
62+
if ('.' == $part) {
63+
continue;
64+
} elseif ('..' == $part) {
65+
array_pop($absolutes);
66+
} else {
67+
$absolutes[] = $part;
68+
}
69+
}
70+
$path = implode(DIRECTORY_SEPARATOR, $absolutes);
71+
}
72+
73+
if ($pathScheme) {
74+
$path = "{$pathScheme}://{$path}";
75+
}
76+
77+
if ($shouldCheckExistence && !file_exists($path)) {
78+
return false;
79+
}
80+
81+
return $path;
82+
}
83+
}

src/Locator/ComposerLocator.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
namespace Go\ParserReflection\Locator;
1212

1313
use Composer\Autoload\ClassLoader;
14+
use Go\ParserReflection\Instrument\PathResolver;
1415
use Go\ParserReflection\LocatorInterface;
1516
use Go\ParserReflection\ReflectionException;
1617

@@ -50,6 +51,11 @@ public function __construct(ClassLoader $loader = null)
5051
*/
5152
public function locateClass($className)
5253
{
53-
return $this->loader->findFile($className);
54+
$filePath = $this->loader->findFile($className);
55+
if (!empty($filePath)) {
56+
$filePath = PathResolver::realpath($filePath);
57+
}
58+
59+
return $filePath;
5460
}
5561
}

src/ReflectionEngine.php

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
namespace Go\ParserReflection;
1212

13+
use Go\ParserReflection\Instrument\PathResolver;
1314
use PhpParser\Lexer;
1415
use PhpParser\Node;
1516
use PhpParser\Node\Stmt\ClassLike;
@@ -204,6 +205,7 @@ public static function parseClassProperty($fullClassName, $propertyName)
204205
*/
205206
public static function parseFile($fileName, $fileContent = null)
206207
{
208+
$fileName = PathResolver::realpath($fileName);
207209
if (isset(self::$parsedFiles[$fileName])) {
208210
return self::$parsedFiles[$fileName];
209211
}

src/ReflectionFile.php

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
namespace Go\ParserReflection;
1212

1313

14+
use Go\ParserReflection\Instrument\PathResolver;
1415
use PhpParser\Node;
1516
use PhpParser\Node\Name\FullyQualified;
1617
use PhpParser\Node\Stmt\Namespace_;
@@ -50,6 +51,7 @@ class ReflectionFile
5051
*/
5152
public function __construct($fileName, $topLevelNodes = null)
5253
{
54+
$fileName = PathResolver::realpath($fileName);
5355
$this->fileName = $fileName;
5456
$this->topLevelNodes = $topLevelNodes ?: ReflectionEngine::parseFile($fileName);
5557
}

src/ReflectionFileNamespace.php

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
namespace Go\ParserReflection;
1212

13+
use Go\ParserReflection\Instrument\PathResolver;
1314
use Go\ParserReflection\ValueResolver\NodeExpressionResolver;
1415
use PhpParser\Node\Stmt\ClassLike;
1516
use PhpParser\Node\Stmt\Const_;
@@ -73,6 +74,7 @@ class ReflectionFileNamespace
7374
*/
7475
public function __construct($fileName, $namespaceName, Namespace_ $namespaceNode = null)
7576
{
77+
$fileName = PathResolver::realpath($fileName);
7678
if (!$namespaceNode) {
7779
$namespaceNode = ReflectionEngine::parseFileNamespace($fileName, $namespaceName);
7880
}

tests/Locator/ComposerLocatorTest.php

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
namespace Go\ParserReflection\Locator;
3+
4+
use Go\ParserReflection\ReflectionClass;
5+
6+
class ComposerLocatorTest extends \PHPUnit_Framework_TestCase
7+
{
8+
public function testLocateClass()
9+
{
10+
$locator = new ComposerLocator();
11+
$reflectionClass = new \ReflectionClass(ReflectionClass::class);
12+
$this->assertSame(
13+
$reflectionClass->getFileName(),
14+
$locator->locateClass(ReflectionClass::class)
15+
);
16+
}
17+
}

0 commit comments

Comments
 (0)