Re: Reflection to remove final

From: Date: Mon, 11 Aug 2014 10:30:47 +0000
Subject: Re: Reflection to remove final
References: 1  Groups: php.internals 
Request: Send a blank email to internals+get-76420@lists.php.net to get a copy of this message
Hi Tom On 9 August 2014 11:35, Tom Oram <tom@scl.co.uk> wrote: > I've just been looking back at the history of this previous conversation... > > http://marc.info/?l=php-internals&m=132673741606531&w=2 > > as a mockist tester I'd really REALLY like to see this be possible but I > can see the problem with the original patch modifying the actual existing > class. > > One solution I propose is rather than modify it would it be possible for > the reflection class to be able to duplicate the class with the finals > removed so something like this could be possible: > > final class A > { > } > > $r = new ReflectionClass('A'); > > $r->defineExtendableClass('ExtendableA'); > > class MockA extends ExtendabledA > { > } > > I'm unfamiliar with the PHP codebase so I thought I'd just ask here to find > out if it sounds possible before diving into the code Yes it's definitely possible, all you need to do is duplicate the class definition and perform &= ~ZEND_ACC_FINAL on the class entry structure flags, however... Joe Watkins' uopz [1][2] extension already provides a mechanism to do what you want to do. I've not tested this, but I quickly bounced a couple of questions off Joe and I believe this should work: final class A {} class MockA {} uopz_extend('MockA', 'A'); A word of warning though: if a *method* is explicitly declared final (rather than implicitly because the class is final), and the mock overrides this method, this will be checked at runtime and cause a fatal error. In order to work around this, you need to use uopz_flags() as well: class B { final public function c() {} } class MockB { public function c() {} } uopz_flags('B', 'c', ZEND_ACC_PUBLIC); // remove ZEND_ACC_FINAL uopz_flags('B', 'c', ); Note also that if you are using this approach - modifying symbol flags at runtime - it is important that you do not declare the inheritance relationship explicitly (i.e. class MockA extends A {}) as this will error out before the runtime modifications are made. If you want to look at adding similar functionality to reflection, then looking at how uopz works would be a good place to start - but personally I'm not sure if there's any value in this since anyone who wants the functionality can just use uopz. [1] https://github.com/krakjoe/uopz [2] http://php.net/uopz > Thoughts? > > Regards, > Tom Thanks, Chris

« previous php.internals (#76420) next »