Coder Social home page Coder Social logo

nette / robot-loader Goto Github PK

View Code? Open in Web Editor NEW
863.0 39.0 32.0 247 KB

๐Ÿ€ RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.

Home Page: https://doc.nette.org/robotloader

License: Other

PHP 100.00%
nette nette-framework php autoload autoloader class-loader comfort php-files composer

robot-loader's Introduction

RobotLoader

Downloads this Month Tests Coverage Status Latest Stable Version License

Introduction

RobotLoader is a tool that gives you comfort of automated class loading for your entire application including third-party libraries.

โœ… get rid of all require
โœ… doesn't require strict naming conventions for directories or files
โœ… extremely fast
โœ… no manual cache updates, everything runs automatically
โœ… mature, stable and widely used library

Thus, we can forget about these familiar code blocks:

require_once 'Utils/Page.php';
require_once 'Utils/Style.php';
require_once 'Utils/Paginator.php';
...

ย 

Do you like RobotLoader? Are you looking forward to the new features?

Buy me a coffee

Thank you!

ย 

Installation

You can download RobotLoader as a single standalone file RobotLoader.php, which you include using require in your script, and instantly enjoy comfortable autoloading for the entire application.

require '/path/to/RobotLoader.php';

$loader = new Nette\Loaders\RobotLoader;
// ...

If you're building an application using Composer, you can install it via:

composer require nette/robot-loader

It requires PHP version 8.0 and supports PHP up to 8.4.

ย 

Usage

Similar to how the Google robot crawls and indexes web pages, the RobotLoader goes through all PHP scripts and notes which classes, interfaces, traits and enums it found. It then stores the results in cache for use in subsequent requests. You just need to specify which directories it should go through and where to store the cache:

$loader = new Nette\Loaders\RobotLoader;

// Directories for RobotLoader to index (including subdirectories)
$loader->addDirectory(__DIR__ . '/app');
$loader->addDirectory(__DIR__ . '/libs');

// Set caching to the 'temp' directory
$loader->setTempDirectory(__DIR__ . '/temp');
$loader->register(); // Activate RobotLoader

And that's it, from this point on, we don't need to use require. Awesome!

If RobotLoader encounters a duplicate class name during indexing, it will throw an exception and notify you. RobotLoader also automatically updates the cache when it needs to load an unknown class. We recommend turning this off on production servers, see [#Caching].

If you want RobotLoader to skip certain directories, use $loader->excludeDirectory('temp') (can be called multiple times or pass multiple directories).

By default, RobotLoader reports errors in PHP files by throwing a ParseError exception. This can be suppressed using $loader->reportParseErrors(false).

ย 

PHP Files Analyzer

RobotLoader can also be used purely for finding classes, interfaces, traits and enums in PHP files without using the autoloading function:

$loader = new Nette\Loaders\RobotLoader;
$loader->addDirectory(__DIR__ . '/app');

// Scans directories for classes/interfaces/traits/enums
$loader->rebuild();

// Returns an array of class => filename pairs
$res = $loader->getIndexedClasses();

Even with such usage, you can utilize caching. This ensures that unchanged files won't be rescanned:

$loader = new Nette\Loaders\RobotLoader;
$loader->addDirectory(__DIR__ . '/app');

// Set caching to the 'temp' directory
$loader->setTempDirectory(__DIR__ . '/temp');

// Scans directories using cache
$loader->refresh();

// Returns an array of class => filename pairs
$res = $loader->getIndexedClasses();

ย 

Caching

RobotLoader is very fast because it cleverly uses caching.

During development, you hardly notice it running in the background. It continuously updates its cache, considering that classes and files can be created, deleted, renamed, etc. And it doesn't rescan unchanged files.

On a production server, on the other hand, we recommend turning off cache updates using $loader->setAutoRefresh(false) (in a Nette Application, this happens automatically), because files don't change. At the same time, it's necessary to clear the cache when uploading a new version to hosting.

The initial file scanning, when the cache doesn't exist yet, can naturally take a moment for larger applications. RobotLoader has built-in prevention against cache stampede. This is a situation where a large number of concurrent requests on a production server would trigger RobotLoader, and since the cache doesn't exist yet, they would all start scanning files, which would overload the server. Fortunately, RobotLoader works in such a way that only the first thread indexes the files, creates the cache, and the rest wait and then use the cache.

ย 

PSR-4

Nowadays, you can use Composer for autoloading while adhering to PSR-4. Simply put, it's a system where namespaces and class names correspond to the directory structure and file names, e.g., App\Router\RouterFactory will be in the file /path/to/App/Router/RouterFactory.php.

RobotLoader isn't tied to any fixed structure, so it's useful in situations where you don't want to have the directory structure designed exactly like the PHP namespaces, or when developing an application that historically doesn't use such conventions. It's also possible to use both loaders together.

If you like RobotLoader, please make a donation now. Thank you!

robot-loader's People

Contributors

dg avatar diegosardina avatar discorddottest avatar fprochazka avatar janbarasek avatar jantvrdik avatar josefsabl avatar jsmitka avatar kravco avatar majkl578 avatar milo avatar vasekpurchart avatar vlastavesely avatar vojtech-dobes avatar vrana avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

robot-loader's Issues

Support for PHP Enums

PHP Enum RFC is currently being voted, and it's highly likely that it will pass.

Enums support autoloading, and it introduces a new T_ENUM token. I would like to suggest that we introduce support to autoload Enums from robot-loader.

Improve robot-loader to look for T_ENUM token if the PHP version is >= 80100, and include it in the autoload list.

Using sys_get_temp_dir() path for temp directory throws exception on second run

  • bug report? yes
  • version: 3.0.2

Description

  • 1st run works ok.
  • 2nd run throws this exception:
 [RuntimeException]                                                                  
  Unable to create '/tmp/_rector_robot_loader/e56f26b0a961cd5321a1e51348833bf5.php'.

Steps To Reproduce

$robotLoader = new RobotLoader();
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/_rector_robot_loader');

$robotLoader->addDirectory(__DIR__);

$robotLoader->register();

Feature req: Exclude dirs

I have a lot of folders and subfolders like demos, tests, forum, upload and etc.. some of them contain a lot of files and subdirs...
My question is: if there is a option for exclude dirs will be better and faster solution for robotloader ?
$loader->UnloadDirs("tests,forum,upload"); - something like this with comma separator, or:
$loader->UnloadDir("tests");
$loader->UnloadDir("forum");
$loader->UnloadDir("upload");

RobotAutoloader not load a interface

Version: Last

I see this error - stripe/stripe-php#1601 in my stripe api.
I write there and i write here :)
The error is because autoloader not load a exception interface. I open the cache and i see only one interface:

    'Stripe\\Exception\\OAuth\\ExceptionInterface' => 
    array (
      0 => 'C:\\xampp2\\htdocs\\ext\\pok4\\shop\\stripe\\lib\\Exception\\OAuth\\ExceptionInterface.php',
      1 => 1696003164,
    ),

in the bottom of the cache i see this:
'C:\\xampp2\\htdocs\\ext\\pok4\\shop\\stripe\\lib\\Exception\\ExceptionInterface.php' => 1696003164,
maybe this is the problem - this is not load in the above clasess...

The content of this file is

<?php

namespace Stripe\Exception;

// TODO: remove this check once we drop support for PHP 5
if (\interface_exists(\Throwable::class, false)) {
    /**
     * The base interface for all Stripe exceptions.
     */
    interface ExceptionInterface extends \Throwable
    {
    }
} else {
    /**
     * The base interface for all Stripe exceptions.
     */
    // phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
    interface ExceptionInterface
    {
    }
    // phpcs:enable
}

Do you have any ideas how to load this in robotautoloader ?

Curly braced variables in strings break class scanning

Version: 4.0.0

Bug Description

Whenever there's a curly braced variable in a string ("{$var}"), $level in scanPhp() is increased twice. As a result, any class within the same file following such token is ignored.

Steps To Reproduce

<?php

print "Hello {$World}!";

class Bar // This class won't be found.
{
    function fn()
    {
    }
}

Issue is not present in v3.

Update to v3.3.1 on PHP 7.3 throw error on composer

Version: 3.3.1
PHP: 7.3

Bug Description

After update from v3.3.0 to v3.3.1 an error appear :

$ composer update
[...]
Generating autoload files
                                                                                                                                                                             
  [RuntimeException]                                                                                                                                                         
  Could not scan for classes inside "/home/a/project/vendor/nette/robot-loader/src/" which does not appear to be a file nor a folder  
                                                                                                                                                                             

Possible Solution

Temporarily fix version 3.3.0 in composer.json

saveCache does not use lock

  • bug report? yes
  • version: 3.0.1

saveCache does not use lock and therefore it may fail on this line with following error

E_WARNING: rename(/root/ss/temp/tests/cache/Nette.RobotLoader/b118fb0ce0dea7bbc63b1ce28466196d.php.tmp,/root/ss/temp/tests/cache/Nette.RobotLoader/b118fb0ce0dea7bbc63b1ce28466196d.php): No such file or directory
   
   in /root/ss/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php(414) rename()
   in /root/ss/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php(96) Nette\Loaders\RobotLoader->saveCache()
   in [internal function]Nette\Loaders\RobotLoader->tryLoad()
   in [internal function]spl_autoload_call()
....

Exlude dir does not work with relative (../..) parent dir

  • bug report? yes
  • feature request? no
  • version: 3.0.2

Description

In Nette application bootstrap, I call:

$configurator->createRobotLoader()
	->addDirectory(__DIR__)
	->addDirectory(__DIR__ . '/../lib')
	->excludeDirectory(__DIR__ . '/../lib/tcpdf')
	->register();

but exclusion does not work because on line

$path = str_replace('\\', '/', $dir->getPathname());

leads to

$disallow === [
    "D:/Web/project/lib/tcpdf" => true,
];

$path === "D:/Web/project/app/../lib/tcpdf";

I have two solutions in my mind:

  1. Convert path to realpath in addDirectory() and:
    a) ignore missing paths
    b) throw an exception on missing paths (BC break probability)
  2. Modify mentioned line from $dir->getPathname() to $dir->getRealPath().

Which fix would you prefer? Another one?

subtle changes after fixing #11

Version: dev-master

Bug Description

After file locking changes in #11 we can't have read-only cache.
We are getting errors like

PHP Warning:  fopen(/xxx/xxx/xxx//temp/3f6807b4367423b13920e6b4e953892d.php): failed to open stream: Permission denied in /xxx/xxx/xxx/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php on line 414

Warning: fopen(/xxx/xxx/xxx//temp/3f6807b4367423b13920e6b4e953892d.php): failed to open stream: Permission denied in /xxx/xxx/xxx/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php on line 414
PHP Fatal error:  Uncaught RuntimeException: Unable to create or acquire shared lock on file '/xxx/xxx/xxx//temp/3f6807b4367423b13920e6b4e953892d.php'. in /xxx/xxx/xxx/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php:416
Stack trace:
#0 /xxx/xxx/xxx/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php(77): Nette\Loaders\RobotLoader->loadCache()
#1 /xxx/xxx/xxx/noir-api/kernel.php(45): Nette\Loaders\RobotLoader->register()
#2 /xxx/xxx/xxx/app/cli/worker.php(21): require('/xxx/xxx/xxx...')
#3 {main}
  thrown in /xxx/xxx/xxx/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php on line 416

Fatal error: Uncaught RuntimeException: Unable to create or acquire shared lock on file '/xxx/xxx/xxx//temp/3f6807b4367423b13920e6b4e953892d.php'. in /xxx/xxx/xxx/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php:416
Stack trace:
#0 /xxx/xxx/xxx/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php(77): Nette\Loaders\RobotLoader->loadCache()
#1 /xxx/xxx/xxx/noir-api/kernel.php(45): Nette\Loaders\RobotLoader->register()
#2 /xxx/xxx/xxx/app/cli/worker.php(21): require('/xxx/xxx/xxx...')
#3 {main}
  thrown in /xxx/xxx/xxx/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php on line 416

file cache permissions are:

$ ls -la temp/3f6807b4367423b13920e6b4e953892d.php
-rw-r--r-- 1 app app 10913 Feb 24 16:26 temp/3f6807b4367423b13920e6b4e953892d.php

we have successfully used: on deploy we generate our class cache. web server is not allowed to
change class cache file due permissions. Everything works fine until #11

Steps To Reproduce

generate cache with one user, and try to use it with another

Expected Behavior

To works like before

Possible Solution

revert everything until 180f89e
and it works like a charm

Add $loader->disallow

A $loader->disallow($path) function would be nice to have, and less awkward than creating a file to instruct the loader which paths to disallow.

ExcludeFiles [READY CODE]

Ok, i find a way to fix my things in #31
Sorry for my english is not good at all...

Ok, open RobotLoader.php and find:
private array $excludeDirs = [];
after this line add:
private array $excludeFiles = [];

find:

public function excludeDirectory(string ...$paths): static
{
	$this->excludeDirs = array_merge($this->excludeDirs, $paths);
	return $this;
}

after this add:

public function excludeFiles($files)
{
	$this->excludeFiles = $files;
	return $this;
}

find:
exclude($this->ignoreDirs);
make it like this:
exclude($this->ignoreDirs)->exclude($this->excludeFiles);

After that you can use:
$loader->excludeFiles(['sql.php','en.php','es.php','bg.php','fr.php','ru.php','migrate.php']);

excludeDirs is working normal with this addon (i tested it).
Can you commit the changes ? :)

Problems under concurrency

Version: 3.4.2

Bug Description

When running PHPStan with parallelism on a large project, it is possible for the cache to corrupt due to very frequent reads and writes.

Steps To Reproduce

Not really possible.

Expected Behavior

PHPStan should run normally.

Possible Solution

Making a PR request that introduces new configuration options to mitigate the problem when running on dev environments under stress.

Get rid of dependencies and make the autoloader self-contained

It is an ironic situation that in order to use RobotLoader I have to use composer, so that:

  1. Dependencies are fetched (currently there are two of them - nette/finder and nette/utils)
  2. Dependencies can be autoloaded by the composer's autoloading

In your documentation, you're claiming that RobotLoader can replace composer autoloading, but the only easy way to use it in this mode is to ... install it and autoload it with using composer.

My suggestion is to make RobotLoader a self-contained file with zero dependencies. So then the simplest use case becomes possible: download the single RobotLoader.php file manually, throw it into the source folder, and start using it as the autoloader in the user project.

Ambiguous class $NAME resolution error when there two or more Classes with same name in separate folders

Version: 3.2.0

Bug Description

Getting Ambiguous class $NAME resolution error if there two or more Classes with same name in different folders.

Example: I have
/app/src/legacy/category/default/actions/CreateAction.php
/app/src/legacy/tags/default/actions/CreateAction.php
and,
when I use "/app/src/legacy/" as autoload_directories (automap) then getting following error.
Ambiguous class CreateAction resolution; defined in /app/src/legacy/category/default/actions/CreateAction.php and in /app/src/legacy/tags/default/actions/CreateAction.php.

same error even if I use multiple autoload_directories as:
/app/src/legacy/category/default/actions/
/app/src/legacy/tags/default/actions/

Possible Solution

Something wrong at line 221 in RobotLoader.php
if (isset($info['file'])) { throw new Nette\InvalidStateException("Ambiguous class $class resolution; defined in {$info['file']} and in $file."); }
If I comment-out these lines then everything seems working fine.
:)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.