Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 34 additions & 28 deletions src/AutoloadCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,61 +9,67 @@

namespace AdrianSuter\Autoload\Override;

use function array_keys;
use function file_exists;
use function glob;
use function is_dir;
use function realpath;

/**
* @package AdrianSuter\Autoload\Override
*/
class AutoloadCollection
{
/**
* @var bool[]
* @var bool[] The keys of this associative array are the file paths.
*/
private $paths = [];
private $filePaths = [];

/**
* @param string $path
* Add a file to the autoload collection.
*
* This method would ignore the file if it could not be found.
*
* @param string $path The path to the file.
*/
public function addFile(string $path): void
{
$path = \realpath($path);
if ($path !== false) {
$this->paths[$path] = true;
}
}

/**
* @param string[] $directories
*/
public function addDirectories(array $directories): void
{
foreach ($directories as $directory) {
try {
$this->addDirectory($directory);
} catch (\InvalidArgumentException $ignore) {
}
$realpath = realpath($path);
if ($realpath !== false) {
$this->filePaths[$realpath] = true;
}
}

/**
* @param string $directory
* Add a directory, i.e. the php files inside a directory.
*
* This method would ignore the directory if it could not be found.
*
* @param string $directory The directory.
*/
public function addDirectory(string $directory)
public function addDirectory(string $directory): void
{
if (
!\file_exists($directory) ||
!\is_dir($directory) ||
false === ($directory = \realpath($directory))
!file_exists($directory) ||
!is_dir($directory) ||
false === ($directory = realpath($directory))
) {
throw new \InvalidArgumentException('Directory could not be found.');
return;
}

$files = \glob($directory . '/*.php');
$files = glob($directory . '/*.php');
foreach ($files as $file) {
$this->addFile($file);
}
}

/**
* @return string[]
* Get the file paths.
*
* @return string[] The file paths.
*/
public function getFilePaths(): array
{
return array_keys($this->paths);
return array_keys($this->filePaths);
}
}
39 changes: 28 additions & 11 deletions src/ClosureHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,30 @@
use Closure;
use RuntimeException;

use function call_user_func_array;
use function sprintf;

/**
* The ClosureHandler is a Singleton class to handle overrides defined as closures.
*
* @package AdrianSuter\Autoload\Override
*/
class ClosureHandler
{
/**
* @var self
* @var self The singleton instance.
*/
private static $instance;

/**
* @var Closure[]
* @var Closure[] A list of closures.
*/
private $closures = [];

/**
* @return self
* Get the singleton instance.
*
* @return self The ClosureHandler.
*/
public static function getInstance(): self
{
Expand All @@ -37,28 +47,35 @@ public static function getInstance(): self
}

/**
* @param string $name
* @param Closure $closure
* Add a closure.
*
* This method would overwrite any previously defined closure with the same name.
*
* @param string $name The closure name.
* @param Closure $closure The closure.
*/
function addClosure(string $name, Closure $closure): void
public function addClosure(string $name, Closure $closure): void
{
$this->closures[$name] = $closure;
}

/**
* @param string $name
* @param array $arguments
* Magic call.
*
* @param string $name The method name.
* @param array $arguments The method arguments.
*
* @return mixed
*/
public function __call(string $name, array $arguments)
{
if (isset($this->closures[$name])) {
return \call_user_func_array(
$this->closures[$name], $arguments
return call_user_func_array(
$this->closures[$name],
$arguments
);
}

throw new RuntimeException(\sprintf('Closure Override "%s" could not be found.', $name));
throw new RuntimeException(sprintf('Closure Override "%s" could not be found.', $name));
}
}
70 changes: 44 additions & 26 deletions src/CodeConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,40 +21,51 @@
use PhpParser\Parser\Php7;
use PhpParser\PrettyPrinter\Standard;

use function array_keys;
use function array_values;
use function md5;
use function str_replace;
use function uniqid;

/**
* @package AdrianSuter\Autoload\Override
*/
class CodeConverter
{
private const ATTR_RESOLVED_NAME = 'resolvedName';

/**
* @var Parser
* @var Parser The PHP Parser.
*/
protected $parser;

/**
* @var Lexer
* @var Lexer The PHP Lexer.
*/
protected $lexer;

/**
* @var NodeTraverser
* @var NodeTraverser The PHP Node Traverser.
*/
protected $traverser;

/**
* @var Standard
* @var Standard The PHP Printer.
*/
protected $printer;

/**
* @var NodeFinder
* @var NodeFinder The PHP Node Finder.
*/
protected $nodeFinder;

/**
* @param Lexer|null $lexer The lexer.
* @param Parser|null $parser The parser.
* @param NodeTraverser|null $traverser The traverser - make sure that the traverser has a CloningVisitor and a
* NameResolver visitor.
* @param Standard|null $printer The printer.
* @param NodeFinder|null $nodeFinder The node finder.
* @param Lexer|null $lexer The PHP Lexer.
* @param Parser|null $parser The PHP Parser.
* @param NodeTraverser|null $traverser The PHP Node Traverser - make sure that the traverser has a CloningVisitor
* and a NameResolver visitor.
* @param Standard|null $printer The PHP Printer.
* @param NodeFinder|null $nodeFinder The PHP Node Finder.
*/
public function __construct(
?Lexer $lexer = null,
Expand All @@ -63,9 +74,11 @@ public function __construct(
?Standard $printer = null,
?NodeFinder $nodeFinder = null
) {
$this->lexer = $lexer ?? new Emulative([
'usedAttributes' => ['comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos'],
]);
$this->lexer = $lexer ?? new Emulative(
[
'usedAttributes' => ['comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos'],
]
);

$this->parser = $parser ?? new Php7($this->lexer);

Expand All @@ -82,10 +95,10 @@ public function __construct(
}

/**
* Convert the given code.
* Convert the given source code.
*
* @param string $code
* @param array $functionCallMappings
* @param string $code The source code.
* @param array $functionCallMappings The function call mappings.
*
* @return string
*/
Expand All @@ -100,21 +113,26 @@ public function convert(string $code, array $functionCallMappings): string
$funcCalls = $this->nodeFinder->findInstanceOf($newStmts, FuncCall::class);
foreach ($funcCalls as $funcCall) {
/** @var FuncCall $funcCall */
if ($funcCall->name->hasAttribute('resolvedName')) {
/** @var FullyQualified $resolvedName */
$resolvedName = $funcCall->name->getAttribute('resolvedName');
$resolvedNameCode = $resolvedName->toCodeString();
if (!$funcCall->name->hasAttribute(self::ATTR_RESOLVED_NAME)) {
continue;
}

/** @var FullyQualified $resolvedName */
$resolvedName = $funcCall->name->getAttribute(self::ATTR_RESOLVED_NAME);

if (isset($functionCallMappings[$resolvedNameCode])) {
$k = uniqid(md5($resolvedNameCode), true);
$overridePlaceholders[$k] = $functionCallMappings[$resolvedNameCode];
$resolvedNameCode = $resolvedName->toCodeString();
if (isset($functionCallMappings[$resolvedNameCode])) {
$k = uniqid(md5($resolvedNameCode), true);
$overridePlaceholders[$k] = $functionCallMappings[$resolvedNameCode];

$funcCall->name = new FullyQualified($k);
}
$funcCall->name = new FullyQualified($k);
}
}

$code = $this->printer->printFormatPreserving($newStmts, $oldStmts, $oldTokens);
if (empty($overridePlaceholders)) {
return $code;
}

return str_replace(array_keys($overridePlaceholders), array_values($overridePlaceholders), $code);
}
Expand Down
Loading