Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

More refactoring for AutoloadGenerator #2298

Closed
wants to merge 10 commits into from

5 participants

@donquixote

Follow-up to the refactoring PR for AutoloadGenerator. #2142

Goal:

  • eliminate method parameter madness
  • eliminate local variable madness
  • avoid classes and methods being too long
  • Split the generator into "aspects"
  • Improve documentation
  • Make it look nice in PHPStorm.
@donquixote

@Seldaek: Please don't merge this as-is. I want to clean up the git history (rebase) and we probably want to rename some methods..

@donquixote

And merging with master is going to be fun...

@igorw igorw commented on the diff
...omposer/Autoload/Generator/AutoloadGenerationTask.php
((243 lines not shown))
+
+ foreach (new \RecursiveIteratorIterator(new \RecursiveArrayIterator($this->autoloads['classmap'])) as $dir) {
+ $aspect->scanDir($dir);
+ }
+
+ return $aspect;
+ }
+
+ /**
+ * @return Aspect\TargetDirAspect|null
+ */
+ protected function get_targetDirAspect()
+ {
+ // Add custom psr-0 autoloading, if the root package has a target dir.
+ $mainAutoload = $this->mainPackage->getAutoload();
+ if (1
@igorw
igorw added a note

what is this for? :)

to line up the && nicely, and make it easy to rearrange conditions.. similar to the comma after a last element in an array.
i don't insist on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@igorw igorw commented on the diff
...Generator/Aspect/AutoloadGeneratorAspectInterface.php
((3 lines not shown))
+namespace Composer\Autoload\Generator\Aspect;
+
+use Composer\Autoload\Generator\AutoloadGenerationTask;
+
+interface AutoloadGeneratorAspectInterface {
+
+ /**
+ * Generates the autoload_classmap.php, typically in (project root)/vendor/composer/autoload_classmap.php
+ * Returns the PHP code snippet for AutoloaderInit::getLoader() that will register the class map to the class loader.
+ *
+ * @param AutoloadGenerationTask $task
+ * Information about the current autoload generation task.
+ * @return string
+ * PHP snippet for AutoloaderInit::getLoader().
+ */
+ public function dumpAndGetSnippet(AutoloadGenerationTask $task);
@igorw
igorw added a note

Maybe dumping and the snippet should be two separate operations? Especially considering one of them is a command and the other is a query.

yes they should.
there are "historic" reasons why they are in the same method.
and one practical motivation was that we might reuse some variable.
but none of that is a real reason not to split it up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@igorw igorw commented on the diff
...omposer/Autoload/Generator/AutoloadGenerationTask.php
((68 lines not shown))
+ * @todo verify required keys?
+ * Not doing this allows to use an incomplete version of this, if only one or a few values are needed.
+ * See e.g. AutoloadGenerator::buildPackageMap()
+ */
+ public function __construct(array $data)
+ {
+ $this->data = $data;
+ }
+
+ /**
+ * Gets a lazy value.
+ *
+ * @param $key
+ * @return mixed
+ */
+ public function __get($key)
@igorw
igorw added a note

Why this crazy magic getter? I think normal getters would already make this code a lot clearer.

Because this allows type hints in the IDE via the @property statements in the above docblock.

@igorw
igorw added a note

But if you put a @return docblock, you don't need the @property.

ah, you mean one getter per property, and then if we want a lazy cache, we do that explicitly per method?
I somehow got used to the pattern of a central cache mechanic.. but i might be totally off with that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@igorw igorw commented on the diff
...omposer/Autoload/Generator/AutoloadGenerationTask.php
((57 lines not shown))
+class AutoloadGenerationTask {
+
+ /**
+ * @var array
+ * Lazy-generated data.
+ */
+ protected $data = array();
+
+ /**
+ * @param array $data
+ * Starting values for some data keys.
+ * @todo verify required keys?
+ * Not doing this allows to use an incomplete version of this, if only one or a few values are needed.
+ * See e.g. AutoloadGenerator::buildPackageMap()
+ */
+ public function __construct(array $data)
@igorw
igorw added a note

This class has no clearly defined responsibilities. Which is an indication that it is doing way too much. The meaning of this class is completely different depending on what you pass to the constructor. Maybe you pass $config, maybe you pass $mainPackage and $localRepo.

Maybe those distinct responsibilities should be split into separate classes or functions.

The role is a bit like a compiled DIC..

@igorw
igorw added a note

A compiled DIC has a clearly defined set of input parameters. In fact, usually it has no input parameters. What is passed as $data to the constructor here is completely arbitrary.

Most of the time when this class is constructed, it's in an incomplete state. In the sense that some methods will blow up due to missing keys.

This class has no clearly defined responsibilities. Which is an indication that it is doing way too much.

Well the original AutoloaderGenerator did everything in one class, so it is really hard to be worse than that :)
But I agree, it may still be too much. i can see a number of things that can be removed from this class and put elsewhere.

One argument to have at least some of this in one class is to allow a shared signature for all "aspects" (or better: "partial generators") and then just iterate over the partial generators.

The difference in dependencies for the generators is too arbitrary to justify separate signatures. Maybe their constructors can have separate signatures, but then the getSnippet() and dump() should have a shared signature defined in the interface.

Knowing that one partial dump() needs a project root dir whereas another needs a vendor dir does not really help to separate responsibilities, it is just too arbitrary.

Most of the time when this class is constructed, it's in an incomplete state.

True. E.g. the usage of AutoloadGenerationTask in buildPackageMap() is very cheap and dirty. Better might be to build the package map somewhere outside.
Although.. it feels so convenient!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on the diff
...omposer/Autoload/Generator/AutoloadGenerationTask.php
((87 lines not shown))
+ }
+ return $this->data[$key] = $this->{'get_' . $key}();
+ }
+
+ /**
+ * @return bool
+ */
+ protected function get_useGlobalIncludePath()
+ {
+ return (bool) $this->config->get('use-include-path');
+ }
+
+ /**
+ * @return array
+ */
+ protected function get_packageMap()
@stof
stof added a note

Please update the whole PR to follow the PSR-2 coding standards

Are you talking about the underscore?
Imo it is legitimate to put an underscore in "synthesized" method names, precisely to make them distinguishable from regular user-invented names. I dunno if PSR-2 says anything about that, will check.
Of course, you could disagree with the entire magic stuff from __get()...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on the diff
...mposer/Autoload/Generator/AutoloadGeneratorHelper.php
((19 lines not shown))
+return ComposerAutoloaderInit{$task->suffix}::getLoader();
+
+AUTOLOAD;
+ file_put_contents($task->vendorPath.'/autoload.php', $php);
+ }
+
+ /**
+ * @param AutoloadGenerationTask $task
+ * @param string $loaderSetupCode
+ * @param string $extraMethodsCode
+ * @return bool
+ */
+ public function dumpAutoloadRealFile($task, $loaderSetupCode, $extraMethodsCode)
+ {
+ // TODO the class ComposerAutoloaderInit should be revert to a closure
+ // when APC has been fixed:
@stof
stof added a note

It will probably never be fixed as the development of the APC opcode cache has been stopped since the inclusion of Opcache in PHP 5.5.
So the revert to a closure would be possible only once bumping the minimal version to 5.5 (when APC is not considered anymore)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Seldaek Seldaek closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 1, 2013
  1. @donquixote

    AutoloadGenerator: Most methods that depend on filesystem stuff are f…

    donquixote authored
    …actored out into AutoloadGeneratorHelper.
  2. @donquixote
  3. @donquixote
Commits on Sep 27, 2013
  1. @benjisg @donquixote
  2. @donquixote

    Add as an explicit property in AutoloadGeneratorHelper. (It is alread…

    donquixote authored
    …y being used in dumpAutoloadRealFile(), it just wasn't an explicit property)
  3. @donquixote
Commits on Sep 28, 2013
  1. @donquixote

    Refactor AutoloadGenerator: 1. Move each 'aspect' into its own class.…

    donquixote authored
    … 2. Fight paramter madness by introducing a AutoloadGenerationTask lazy value container.
  2. @donquixote

    fix line endings

    donquixote authored
  3. @donquixote

    some comments added

    donquixote authored
  4. @donquixote

    fix line endings

    donquixote authored
Something went wrong with that request. Please try again.