2017 © Pedro Peláez
 

composer-plugin composer-class-rewrite

Composer plugin to handle class rewrite

image

macfja/composer-class-rewrite

Composer plugin to handle class rewrite

  • Tuesday, January 26, 2016
  • by MacFJA
  • Repository
  • 1 Watchers
  • 1 Stars
  • 13 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 2 Versions
  • 0 % Grown

The README.md

Composer Class-Rewrite

Latest Version Software License Total Downloads, (*1)

What is Composer Class-Rewrite

Composer Class-Rewrite is a Composer plugin that allow you to rewrite almost[1]1 any classes of your project., (*2)

Principle[2][^2]

The idea is to scan every classes of the project to find classes declared as a rewrite. Then we make some modification on the parent (rewritten) class (_a copy of the parent class_) and the rewriter class (_a copy of the rewriter class_) and finally add them to the Composer autoload (before PSR-0 and PSR-4 classes). So, when a class ask for the rewritten class, Composer will return our modified rewiter class., (*3)

Installation

With Composer:, (*4)

$ composer require macfja/composer-class-rewrite

Usage

# File:  example/A.php
namespace Example;
class A
{
    public function who()
    {
        return 'A';
    }
}

```php, (*5)

File: example/B.php

namespace Example; class B extends A { public function who() { return parent::who() . '-B'; } }, (*6)

```php
# File:  example/C.php
namespace Example;
class C extends A implements \MacFJA\ClassRewrite\Rewriter
{
    public function who()
    {
        return parent::who() . '-C';
    }
}

```sh $ composer dump-autoload # Mandatory after any changes in Example\A or in Example\C, (*7)

```php
$b = new B();
echo $b->who(); // Output: "A-C-B"

Limitations

  • Only work for PSR-0 and PSR-4 namespace.
  • Only work if Composer is the first autoloader.
  • Only work on non-dev dependency.
  • Only work on class (not on trait, nor on interface).
  • The rewriter class MUST have the same namespace than the rewritten class.
  • You have to rebuild the autoload for every rewriter/rewritten changes.
  • Have some side effects (see example below)
    • Class context is changed (magic constants).
    • Multiple call if you instanciate the rewriter class.

Side effects

Multiple call

# File:  example/A.php
namespace Example;
class A
{
    public function who()
    {
        return 'A';
    }
}
````
```php
# File:  example/B.php
namespace Example;
class B extends A implements \MacFJA\ClassRewrite\Rewriter
{
    public function who()
    {
        return parent::who() . '-B';
    }
}

```php, (*8)

File: example/C.php

namespace Example; class C extends B { public function who() { return parent::who() . '-C'; } }, (*9)

```php
# File: test.php
require 'vendor/autoload.php';
$class = new A();
echo $class->who(); //output A-B

$class2 = new B();
echo $class2->who(); // output A-B-B
// -> the output is (A='A-B', parent of B) + '-B' (from B)

$class3 = new C();
echo $class3->who(); // output A-B-B-C
// -> the output is (A='A-B', parent of B) + '-B' (from B, parent of C) + '-C' (from C)
```

#### Magic constants

```php
# File:  example/A.php
<?php
namespace Example;
class A
{
    public function dir()
    {
        return __DIR__; // "~/example"
    }
    public function thisClass()
    {
        return __CLASS__; // "Example\A"
    }
}

```php, (*10)

File: example/B.php

<?php namespace Example; class B extends A implements \MacFJA\ClassRewrite\Rewriter { public function dir() { return DIR; // "~/example" } } ````, (*11)

# File: test.php
require 'vendor/autoload.php';
$class = new A();
echo $class->dir(); //output "~/vendor/_rewrite"
echo $class->thisClass(); //output "Example\Cc09c111b433d2b65b9b01c999ae6480874b076a8"
echo get_class($class); //output "Example\A"

Explored ideas

  1. Inject my code during the Composer autoloading. Issue: Composer don't provide event in autoloader.
  2. Change the Composer autoloader code to add my logic. Issue: Change core code. So if Composer change it, he have to change mine too. Hard to maintain.
  3. Prepend a customer autoloader before Composer autoloader. Issue: Loose all the power of Composer autloading.

Under the hood

This plugin use:, (*12)

  • composer-plugin-api (obvious)
  • nikic/php-parser: For parsing php class, and rewrite them

How it works

Just before Composer autoloader generation, the plugin is parsing every PSR-0 and PSR-4 namespace. It search for class that implement the interface \MacFJA\ClassRewrite\Rewriter, store in memory the the rewriter class and the rewritten class. When the plugin have parse every classes. It rebuild every Rewriter and Rewritten class for rename the Rewritten classname with a hard to guess class name (in fact, it's a sha1 of the source file) and to rename the Rewriter classname into the original Rewritten classname. Finally it add the rewrite destination directory into Composer classmap autoload.
Then it let Composer do it's stuff., (*13)

It's works because Composer start searching class in the classmap autoload., (*14)

License

The MIT License (MIT). Please see License File for more information., (*15)

  1. #how-it-works "For more information on how it works, see the How it works section" , (*16)

The Versions

26/01 2016

dev-master

9999999-dev

Composer plugin to handle class rewrite

  Sources   Download

MIT

The Requires

 

The Development Requires

rewrite composer class rewrite

26/01 2016

v0.1.0

0.1.0.0

Composer plugin to handle class rewrite

  Sources   Download

MIT

The Requires

 

The Development Requires

rewrite composer class rewrite