Home  >  Q&A  >  body text

Extend PHP classes used internally without changing dependencies

I want to override a PHP class in Laravel, but it is being extended by several other classes that I don't want to bother with. The overall structure is as follows

class A extends R { }
class B extends R { }
class C extends R { }
class D extends R { }

Where A/B/C/D/R are all classes in the external package.

I want to extend A/B/C/D to P without changing any of those files (which would be a maintenance burden), so that the P class extends R. So I can make additions to the P class.

I've been looking into class_alias() which allows me to connect to the autoloader. This will load class P correctly.

The code I used is:

// Some bootstrap file:
class_alias(
    P::class,
    R::class
);
// My modification:
class P extends R
{
    // ...
}

But I got an error:

ErrorException: Cannot declare class R because the name is already in use

I'm looking for a solution that can extend an inner PHP class while preventing the full file contents of the class from being copied. I don't even know if it can be done. The class I want to extend does not fit into the Laravel service container, so there is no first-party way to add functionality.

P粉278379495P粉278379495257 days ago312

reply all(1)I'll reply

  • P粉189606269

    P粉1896062692024-01-11 00:08:07

    class_alias by itself is not enough, because in order for P to extend R, both classes must exist. And class_alias has nothing to do with autoloading, it just declares a class with two names.

    What you actually need is to define a real class R with a new name, and then define your own class with the name R (you don't actually need class_alias).

    One approach is to dynamically rewrite the source code of the target class and then load the modified copy, as shown below (untested):

    $code = file_get_contents(__DIR__ . '/vendor/path/to/R.php');
    $code = str_replace('class R', 'class R_original', $code);
    eval($code);
    
    class R extends R_original {
       // Your code here
    }

    Importantly, this needs to be run before the normal autoloader attempts to define the class. For example, you can use spl_autoload_register with the $prepend option set to true.

    reply
    0
  • Cancelreply