Breaking inheritance in object orientated PHP

Dougall Winship

Senior AI & Software Developer

Published:

** Warning : do not do this! **

Using a combination of PHP's magic methods and reflection it's possible to nearly completely sidestep PHP's OO inheritance visibility. Obviously this isn't a good thing under very nearly all circumstances ... just because you can do something doesn't mean you should!

 

The technique is very simple ... you intercept calls made to private methods/attributes using PHP's magic methods __get __set __call and __callStatic, find the private method or attribute in question and force it to be available via reflection's setAccessible(...) method.

 

Note that you'll probably want to turn on php display errors to run most of the following scripts, something like this:

First, to illustrate the technique, let's consider a very simple case:

If you attempt to run this then for obvious reasons you will get an error like this Uncaught Error: Cannot access private property CTest::$privateAttribute in .....

However PHP's reflection system allows us to ignore this restriction like so:

If you run this code you will see 'private value' output.

Next consider this code:

If you try to run this then again you will get an error (well technically a notice in this case) Notice: Undefined property: CTest::$privateAttribute since the parent's privateAttribute is unavailable to the inheriting class, *but* PHP's magic methods allow us to catch this attempt and do something with it, in this case we can force the attribute to be visible via reflection in the manner previously described, this gives us:

OK great, so now we have this ill advised technique working let's make it a trait so we can abuse our PHP code more easily:

Loathe as I am to call this "neater" it arguably has an ugly sort of elegance to it.

There's a few things to note at this stage:

  • The same technique can be used/abused for methods and static methods.

  • PHP's class_parents returns all the named class's parents

  • We may as well cache the ReflectionClass(es)

So combining all this together, here is the final monstrous creation:

You can take this for a ride using something like the following:

Please, please, please bear in mind that in most circumstances this is clearly a very bad idea, it should be considered more of a curiosity than anything actually useful.

Pretty much the only justification for doing something like this that I can think of is when you want to extend a 3rd party library class with the following characteristics:

  • It has inadequate attribute/method visibility (e.g. overriding a protected method which makes private calls you want to retain) for extensibility.

  • It is liable to have frequent updates (maybe to mitigate security issues)

  • ...and you have an enormous large codebase and cannot realistically audit everything in detail when upgrading

Normally this isn't a problem, but Magneto...

Finally, please note that aside from the obvious flaws with this oddity there are several gotchas including:

  • It can't work with static attributes as there is not a corresponding magic method in php currently.

  • It hasn't been rigorously tested.

  • It's pretty flakey and may well be broken by future PHP releases.

The code in this blog is available as a zip here. There is a public gist here

Dougall Winship

Senior AI & Software Developer

Reimagine your digital future today

Send us a message for more information about how we can help you and your business

Reimagine your digital future today

Send us a message for more information about how we can help you and your business

Reimagine your digital future today

Send us a message for more information about how we can help you and your business

Reimagine your digital future today

Send us a message for more information about how we can help you and your business

Services

Capabilities

About

Linebreak

New Icon is a Linebreak company

© Newicon Ltd. Registered in England and Wales. Company No: 05904359 | VAT: GB 993768447.

Designed and built by New Icon in Bristol, a Linebreak company.

Linebreak

New Icon is a Linebreak company

© Newicon Ltd. Registered in England and Wales. Company No: 05904359 | VAT: GB 993768447.

Designed and built by New Icon in Bristol, a Linebreak company.

Linebreak

New Icon is a Linebreak company

© Newicon Ltd. Registered in England and Wales. Company No: 05904359 | VAT: GB 993768447.

Designed and built by New Icon in Bristol, a Linebreak company.