Given a PSR-2 compliant PHP class file (or stub)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Car extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
//
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
//
];
}
Is there some tool to easily parse and modify it? In the best of worlds with a fluent API, maybe something like:
PhpClass::make(".../Car.php")
->setNamespace("Some/New/Namespace")
->use("Some\Dependency")
->addMethod($newFunctionBody)
Im aware this might be a naive example, but how close to such a tool is there out there? By tool I mean something I can pull in as a dependency preferably via composer.
Right now I have a somewhat working solution using placeholders and regex but it starts to grow out of control with many edge cases. Therefore im thinking I might need to actually interpret the PHP.
Componere is a PHP 7 extension, available on pecl and documented in the PHP manual ...
The code below registers the definition in the class entry table:
<?php
/* just making the example standalone */
class Model {}
class Car extends Model {
public function something() {}
}
trait SaysVroomVroomWhenPoked {
public function poke() {
return "Vroom Vroom";
}
}
$def = new \Componere\Definition(Some\Place\Car::class, Car::class);
$def->addTrait(SaysVroomVroomWhenPoked::class);
$def->addMethod("newMethod", new \Componere\Method(function(){
return 42;
}));
$def->register();
$car = new \Some\Place\Car();
printf("%s and %d\n", $car->poke(), $car->newMethod());
?>
Registering the class in the entry table may be desirable in some cases, it's effects are application wide for the life of the request.
The code below patches a particular instance of an object with the required features:
<?php
/* just making the example standalone */
class Model {}
class Car extends Model {
public function something() {}
}
trait SaysVroomVroomWhenPoked {
public function poke() {
return "Vroom Vroom";
}
}
function accept(Car $car) {
$patch = new \Componere\Patch($car);
$patch->addTrait(SaysVroomVroomWhenPoked::class);
$patch->addMethod("newMethod", new \Componere\Method(function(){
return 42;
}));
$patch->apply();
printf("%s and %d\n", $car->poke(), $car->newMethod());
}
$car = new Car();
accept($car);
var_dump(method_exists($car, "newMethod")); # false
?>
Note that doing this everywhere is much less efficient than changing the definition, but it's side effects disappear when the accept function returns.
http://php.net/componere
Note: it has a fluid interface, but for the purposes of clarity I did not use it here ...
Edit:
I just noticed your comment expressing an interest in pre-processing code, or possibly using anonymous classes, and not runtime manipulation. Using anonymous classes is an excellent idea, but I don't think you need an example of that ...
Full disclosure: I wrote Componere, and I wrote the implementation of anonymous classes for PHP ...
Anything I say to dissuade you from pre-processing is probably going to be pretty empty now ...
I built a Laravel package for this use case: https://github.com/ajthinking/php-file-manipulator
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With