mirror of
https://github.com/danog/class-finder.git
synced 2025-01-22 13:51:42 +01:00
Implement the mechanism that determines the classes in a file; implement FileEntry::knowsNamespace.
This commit is contained in:
parent
31a4b109ae
commit
4a91665f3a
@ -5,14 +5,25 @@ class FilesEntry
|
||||
{
|
||||
private $file;
|
||||
|
||||
public function __construct($fileToInclude)
|
||||
private $php;
|
||||
|
||||
public function __construct($fileToInclude, $php)
|
||||
{
|
||||
$this->file = $fileToInclude;
|
||||
$this->file = $this->normalizePath($fileToInclude);
|
||||
$this->php = $php;
|
||||
}
|
||||
|
||||
public function knowsNamespace($namespace)
|
||||
{
|
||||
// TODO.
|
||||
$classes = $this->getClassesInFile();
|
||||
|
||||
foreach($classes as $class) {
|
||||
if (strpos($class, $namespace) !== false) {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -23,4 +34,43 @@ class FilesEntry
|
||||
{
|
||||
// TODO.
|
||||
}
|
||||
|
||||
/**
|
||||
* This is where the real magic happens. Since classes in a randomly included file could contain classes in any namespace,
|
||||
* (or even multiple namespaces!) we must execute the file and check for newly defined classes. This has a potential
|
||||
* downside that files being executed will execute their side effects - which may be undesirable. However, Composer
|
||||
* will require these files anyway - so hopefully causing those side effects isn't that big of a deal.
|
||||
* execute the
|
||||
* @return array
|
||||
*/
|
||||
private function getClassesInFile()
|
||||
{
|
||||
// get_declared_classes() returns a bunch of classes that are built into PHP. So we need a control here.
|
||||
$script = "var_export(get_declared_classes());";
|
||||
exec($this->php . " -r \"$script\"", $output);
|
||||
$classes = 'return ' . implode('', $output) . ';';
|
||||
$initialClasses = eval($classes);
|
||||
|
||||
// clear the exec() buffer.
|
||||
unset($output);
|
||||
|
||||
// This brings in the new classes. so $classes here will include the PHP defaults and the newly defined classes
|
||||
$script = "require_once '{$this->file}'; var_export(get_declared_classes());";
|
||||
exec($this->php . ' -r "' . $script . '"', $output);
|
||||
$classes = 'return ' . implode('', $output) . ';';
|
||||
$allClasses = eval($classes);
|
||||
|
||||
return array_diff($allClasses, $initialClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Similar to PSR4Namespace::normalizePath. Maybe we refactor?
|
||||
* @param $path
|
||||
* @return mixed
|
||||
*/
|
||||
public function normalizePath($path)
|
||||
{
|
||||
$path = str_replace('\\', '/', $path);
|
||||
return $path;
|
||||
}
|
||||
}
|
56
src/Files/FilesEntryFactory.php
Normal file
56
src/Files/FilesEntryFactory.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
namespace HaydenPierce\ClassFinder\Files;
|
||||
|
||||
use HaydenPierce\ClassFinder\AppConfig;
|
||||
use HaydenPierce\ClassFinder\Exception\ClassFinderException;
|
||||
|
||||
class FilesEntryFactory
|
||||
{
|
||||
/** @var AppConfig */
|
||||
private $appConfig;
|
||||
|
||||
public function __construct(AppConfig $appConfig)
|
||||
{
|
||||
$this->appConfig = $appConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws ClassFinderException
|
||||
*/
|
||||
public function getFilesEntries()
|
||||
{
|
||||
$files = require($this->appConfig->getAppRoot() . 'vendor/composer/autoload_files.php');
|
||||
$phpPath = $this->findPHP();
|
||||
|
||||
$filesKeys = array_values($files);
|
||||
return array_map(function($index) use ($filesKeys, $phpPath){
|
||||
return new FilesEntry($filesKeys[$index], $phpPath);
|
||||
}, range(0, count($files) - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the PHP interrupter. If PHP 5.4 or newer is used, the PHP_BINARY value is used. Otherwise we attempt to
|
||||
* find it from shell commands.
|
||||
* @return string
|
||||
* @throws ClassFinderException
|
||||
*/
|
||||
private function findPHP()
|
||||
{
|
||||
if (defined(PHP_BINARY)) {
|
||||
// PHP_BINARY was made available in PHP 5.4
|
||||
$php = PHP_BINARY;
|
||||
} else {
|
||||
if (exec('which php', $output)) {
|
||||
$php = $output[0];
|
||||
} elseif (exec('where php', $output)) {
|
||||
$php = $output[0];
|
||||
} else {
|
||||
// TODO: Add link to docs for this.
|
||||
throw new ClassFinderException('Could not locate PHP interrupter.');
|
||||
}
|
||||
}
|
||||
|
||||
return $php;
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
namespace HaydenPierce\ClassFinder\Files;
|
||||
|
||||
use HaydenPierce\ClassFinder\AppConfig;
|
||||
|
||||
class FilesEntryFactory
|
||||
{
|
||||
/** @var AppConfig */
|
||||
private $appConfig;
|
||||
|
||||
public function __construct(AppConfig $appConfig)
|
||||
{
|
||||
$this->appConfig = $appConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFilesEntries()
|
||||
{
|
||||
$files = array();
|
||||
|
||||
$filesKeys = array_keys($files);
|
||||
return array_map(function($index) use ($filesKeys){
|
||||
return new FilesEntry($filesKeys[$index]);
|
||||
}, range(0, count($files) - 1));
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ class FilesFinder implements FinderInterface
|
||||
|
||||
public function isNamespaceKnown($namespace)
|
||||
{
|
||||
$filesEntries = $this->factory->getfilesEntries();
|
||||
$filesEntries = $this->factory->getFilesEntries();
|
||||
|
||||
foreach($filesEntries as $filesEntry) {
|
||||
if ($filesEntry->knowsNamespace($namespace)) {
|
||||
@ -33,11 +33,11 @@ class FilesFinder implements FinderInterface
|
||||
{
|
||||
$filesEntries = $this->factory->getFilesEntries();
|
||||
|
||||
$matchingEntries = array_filter($filesEntries, function(filesEntry $entry) use ($namespace) {
|
||||
$matchingEntries = array_filter($filesEntries, function(FilesEntry $entry) use ($namespace) {
|
||||
return $entry->matches($namespace);
|
||||
});
|
||||
|
||||
return array_map(function(filesEntry $entry) {
|
||||
return array_map(function(FilesEntry $entry) {
|
||||
return $entry->getClassName();
|
||||
}, $matchingEntries);
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
// This is intentionally made global. There are intentionally classes here in and out of a namespace.
|
||||
// PHPStorm is subborn in it's complaining about this - so I just turn off inspections for this file.
|
||||
class my_global_class_name {}
|
||||
|
||||
namespace TestApp1\FilesClasses;
|
||||
|
||||
class Cam {}
|
||||
class Lam {}
|
||||
|
||||
namespace TestApp1\RedHerring;
|
||||
|
||||
class RedHerring {}
|
||||
|
@ -19,6 +19,7 @@ class FilesTest extends \PHPUnit_Framework_TestCase
|
||||
public function testClassFinder($namespace, $expected, $message)
|
||||
{
|
||||
try {
|
||||
ClassFinder::enableFilesSupport();
|
||||
$classes = ClassFinder::getClassesInNamespace($namespace);
|
||||
} catch (\Exception $e) {
|
||||
$this->assertFalse(true, 'An exception occurred: ' . $e->getMessage());
|
||||
|
Loading…
x
Reference in New Issue
Block a user