php - Changing the visibility scope of parent methods in child classes -
i've got validator
class , uservalidator
class extends it.
my validator
has public method setrule(...)
public visibility.
when extend want change visibility of setrule(...)
parent method private/protected within child it's visible child , no outsiders can call method from child.
is possible? if so, how achieve it?
from architectural point of view not recommended. stated in comments clean way set method protected
children can access it.
i cannot think of single use case put me in need call public method on parent class not allowed call on child class.
that's against open/closed principle. classes should open extension, not modification.
since not question i'll provide way how can achieved though. note:
- this method makes use of class responsible instantiation
- it's hack. solution not make use of php's native language features when throwing accessibility errors.
first let's define classes had
<?php class validator { public function setrule() { echo "hello world"; } } class uservalidator extends validator { public $prop = 'property'; }
there's nothing special here. let's go on , create custom exception class visibility error.
<?php class methodnotaccessibleexception extends exception {}
this exception thrown when try invoke "pseudo-private" method on child class.
now want create class responsible instantiating child class. wrapper defines lock
property holds method names should not accessible.
<?php class privateinstancecreator { protected $reflectionclass; protected $lock = []; protected $instance; public function __construct($classname, $args = []) { // we'll store instance of reflection class // , instance of real class $this->reflectionclass = new reflectionclass($classname); $this->instance = $this->reflectionclass->newinstanceargs($args); return $this; } // lock method able make method on // target class "pseudo-private" public function lock($method) { $this->lock[] = $method; return $this; } // real magic going on here // remember. class wrapper real class // if method invoked method // in real instance , invoke it... public function __call($method, $args) { // ... method defined // locked, we'll raise exception method // private if(in_array($method, $this->lock)) { $reflectionmethod = $this->reflectionclass->getmethod($method); if($reflectionmethod->ispublic()) throw new methodnotaccessibleexception('method: __' . $method . '__ private , not invoked'); } return call_user_func_array([$this->instance, $method], $args); } // same goes properties // in case we'll no protection public function __get($prop) { return $this->instance->{$prop}; } }
our final step instantiation.
<?php $uservalidator = new privateinstancecreator('uservalidator', []); $uservalidator->lock('setrule'); $uservalidator->setrule(); //will throw exception
instead of instantiating class directly we'll using our custom wrapper class. of course handle in child class itself, that's way accomplish task without touching classes directly.
having said that, it still dirty hack usage should avoided if possible. if instantiate child class directly inherited methods still public.
so if developer has no knowlege wrapper class he'll have hard time figure out how instantiate child class properly.
update:
to make child class uninstantiable directly can set constructor private
, call newinstancewithoutconstructor()
reflection class, dirtier, since make dependency injection class impossible. i'm mentioning completenesses sake. usage still not recommended
Comments
Post a Comment