I've got a Validator class and a UserValidator class which extends from it.
My Validator has a public method setRule(...) with public visibility.
When I extend from it I want to change the visibility of the setRule(...) parent method to private/protected within the child so that it's only visible for the child and no outsiders can call this method from the child.
Is that possible? If so, how could I achieve it?
From an architectural point of view this is not recommended. As already stated in the comments the clean way would be to set your method to protected so only children can access it.
I cannot think of a single use case that would put me in the need to call a public method on a parent class but where I am not allowed to call it on the child class.
That's against the Open/Closed principle. Classes should be open for extension, but not for modification.
Since that was not the question I'll provide a way how that can be achieved though. But note:
This method makes use of an extra class which will be responsible for the instantiation
It's a hack. This solution will not make use of PHP's native language features when throwing accessibility errors.
First let's define the classes you already had
<?php
class Validator {
public function setRule()
{
echo "Hello World";
}
}
class UserValidator extends Validator {
public $prop = 'PROPERTY';
}
There's nothing special here. So let's go on and create a custom exception class for the visibility error.
<?php
class MethodNotAccessibleException extends Exception {}
This exception will be thrown when we try to invoke a "pseudo-private" method on the child class.
Now we want to create the Class that will be responsible for instantiating your child class. It is basically just a wrapper that defines a lock property which holds method names that should not be accessible.
<?php
class PrivateInstanceCreator {
protected $reflectionClass;
protected $lock = [];
protected $instance;
public function __construct($classname, $args = [])
{
// We'll store an instance of the reflection class
// and an instance of the real class
$this->reflectionClass = new ReflectionClass($classname);
$this->instance = $this->reflectionClass->newInstanceArgs($args);
return $this;
}
// The lock method is able to make a method on the
// target class "pseudo-private"
public function lock($method)
{
$this->lock[] = $method;
return $this;
}
// Some real magic is going on here
// Remember. This class is a wrapper for the real class
// if a method is invoked we look for the method
// in the real instance and invoke it...
public function __call($method, $args)
{
// ... but as soon as this method is defined as
// locked, we'll raise an exception that the method
// is private
if(in_array($method, $this->lock))
{
$reflectionMethod = $this->reflectionClass->getMethod($method);
if($reflectionMethod->isPublic())
throw new MethodNotAccessibleException('Method: __' . $method . '__ is private and could not be invoked');
}
return call_user_func_array([$this->instance, $method], $args);
}
// The same goes for properties
// But in this case we'll do no protection
public function __get($prop)
{
return $this->instance->{$prop};
}
}
Our final step is the instantiation.
<?php
$userValidator = new PrivateInstanceCreator('UserValidator', []);
$userValidator->lock('setRule');
$userValidator->setRule(); //Will throw an exception
Instead of instantiating the class directly we'll do it by using our custom wrapper class.
Of course you could handle it in the child class itself, but that's a way to accomplish your task without touching the classes directly.
Having said that, it is still a dirty hack whose usage should be avoided if possible. If you would instantiate the child class directly the inherited methods would still be public.
So if a developer has no knowlege about the wrapper class he'll have a hard time to figure out how to instantiate the child class properly.
Update:
To make the child class uninstantiable directly you can set the constructor to private and call newInstanceWithoutConstructor() from the reflection class, which is even dirtier, since that would make Dependency Injection for the class completely impossible. I'm just mentioning it for completenesses sake. Usage is still not recommended
Related
So let's say I have classes called parent and child, which will be then used from PHP file called caller.php
class Child extends Parent {
}
class Parent {
public function parentMethod(){
}
}
caller.php
PREVENTED:
$child = new Child();
$child->parentMethod();
ALLOWED:
$parent = new Parent();
$parent->parentMethod();
I want to prevent calling parentMethod like this. But if I created Parent object I want to be able to call the parentMethod. Is there some way that I can use to hide this method from being public in Child class, but still allowing parent object to call this method publicly?
Only solution I have come up with so far is making those methods protected and then creating an other class that would extend parent and then have public method for each function that it needs, but that doesn't sound very smart.
Actually, you should ask yourself: why do you need such restriction? You've defined your method as public - thus, you told PHP that it should be visible everywhere. So to prevent child calls you should use private visibility definition.
There is a way to check if call is made from parent class, like:
class ChildClass extends ParentClass {}
class ParentClass
{
public function parentMethod()
{
if(get_class($this) != __CLASS__)
{
throw new LogicException("Somehow due to business logic you're not allowed to call this from childs");
}
}
}
But I would not recommend to do that. Reasons are:
Readability. Your method is just ordinary public method. Looking to it it's impossible to say either you should use it with child calls or not. Thus, to maintain such code you'll need to check that restriction in code. Now imagine that you have ~50 methods like that. And dozen of classes like that.
Possibly, breaking Law of Demeter. Why should parent class be aware of it's childs when using such limitation?
Finally, it's just unexpected behavior. Looking to definition, anybody will see that you're extending one class by another. Thus, by definition all inherit methods with proper visibility must be inherited. And your logic changes that.
You may think about composition, not inheritance. That may be right way to implement your logic (however, I can't tell that for sure since I don't know whole background)
You can rearrange your code by adding a base parent class for both of your mentioned classes. Like so:
class Base {
public function inheritableMethod1() {}
public function inheritableMethod2() {}
}
class Child extends Base {
}
class Parent extends Base {
public function additionalMethod() {}
}
Move all inheritable methods from the Parent class to the Base, and leave there only those which must not be called on Child (the parentMethod in your example).
The base class optionally might be abstract to prevent instantiating it directly.
Check if Abstract Class suits your needs:
PHP: Class Abstraction
class Child extends Parent {
public function parentMethod(
# Code
}
}
Abstract class Parent {
abstract public function parentMethod();
}
Background
In a project with a PHP 5.6 runtime, I need to work around some third-party code. This code will not be changed by the vendor, nor will it be removed from the codebase.
Specifically, the third-party code (let's call its namespace Theirs) contains a class (\Theirs\BaseClass) whose constructor instantiates another class (\Theirs\Detector).
BaseClassTheirs.php:
<?php namespace Theirs;
class Detector {
public function __construct() {
print "Theirs\n";
}
}
class BaseClass {
public function __construct() {
$detector = new Detector();
}
}
I do not want BaseClass to instantiate \Theirs\Detector. Instead, I want BaseClass to instantiate a different Detector class, from a different namespace (Mine) that is outside of the third-party's control.
In all other respects, though, I want BaseClass to behave as it does in the third-party code, including if the vendor later adds additional functionality to \Theirs\BaseClass. (I'll call this property "non-fragility" and the lack of it "fragility".) As such, it seems sensible for me to create my own \Mine\BaseClass as a child of \Theirs\BaseClass, inheriting everything from it.
If I take the fragile, non-DRY approach of copy-pasting \Theirs\BaseClass's constructor into \Mine\BaseClass, then \Mine\Detector is instantiated, as I desired:
BaseClassMine.php:
<?php namespace Mine;
include "BaseClassTheirs.php";
class Detector {
public function __construct() {
print "Mine\n";
}
}
class BaseClass extends \Theirs\BaseClass {
public function __construct() {
$detector = new Detector();
}
}
\\ Prints "Mine"
$obj = new BaseClass();
However, if I change this into a DRY, non-fragile approach by removing the duplicated code so that \Mine\BaseClass invokes exactly the same constructor, but as inherited from its parent rather than being copy-pasted, then \Theirs\Detector gets invoked, which is not what I want:
BaseClassMine.php:
<?php namespace Mine;
include "BaseClassTheirs.php";
class Detector {
public function __construct() {
print "Mine\n";
}
}
use \Mine\Detector;
class BaseClass extends \Theirs\BaseClass {
}
\\ Prints "Theirs"
$obj = new BaseClass();
This happens regardless of whether the file contains a use \Mine\Detector; line, as above.
Question
How can I get the best of both approaches?
I.e. how can I invoke \Theirs\Baseclass's constructor from \Mine\Baseclass's constructor in order to have it invoke \Mine\Detector, as though \Theirs\Baseclass's constructor had simply been copy-pasted into \Mine\Baseclass's context, but without actually copy-pasting it and introducing the corresponding fragility?
For instance, is there a good way to use reflection or some other introspective technique to dynamically read the parent's constructor and to "paste" it at runtime into the child class?
Related but not identical questions
late static binding | without modifying parent class with static keyword
Is there any way to set a property before calling a constructor?
I'm changing my class structure around to store common database methods in one class. Then extending it from a child class. This should cut down on code but also allows me to overwrite the parent methods when I need to.
I've done the following, for this example I've simplified to the basics compared to the original code which contains more classes.
class parent_object{
private $table_name;
public function all_records(){
$sql = "SELECT * FROM ".$this->table_name;
return $this->execute_sql($sql);
}
}
class child_object extends parent_object{
protected static $table_name="tbl_name";
public function __construct(){
parent::__construct(self::$table_name);
}
}
I want to call the all_records() statically to save myself creating a new object every time.
I'm stuck having to instantiate the child and then call the parent method
$child = new child_object();
$all = $child->all_records();
What I really want to be able to call the parent method statically:
$all = child_object::all_records();
I understand why I can't do it with my code, but would like some way that the child instantiates first then accesses the parent method.
I could write all_records() method in the child_object to instantiate itself and call the parent all_records() but that sort defeats the purpose of extending to cut down on code and the same methods in my child class.
I'm sure its quite simple or some new high level oop function can do it.
Thanks for your help.
The answer is relatively simple, you can turn all your properties into static properties, and then use static:: instead of self::.
http://php.net/manual/en/language.oop5.late-static-bindings.php
Solving your problem this way is considered a bad practice though. Good luck.
You could do something like this:
class child_object extends parent_object
{
protected static $table_name="tbl_name";
public static function factory()
{
return new child_object();
}
public function __construct()
{
parent::__construct(self::$table_name);
}
}
Then when you use it you just do:
$all = child_object::factory()->all_records();
So let's say I have classes called parent and child, which will be then used from PHP file called caller.php
class Child extends Parent {
}
class Parent {
public function parentMethod(){
}
}
caller.php
PREVENTED:
$child = new Child();
$child->parentMethod();
ALLOWED:
$parent = new Parent();
$parent->parentMethod();
I want to prevent calling parentMethod like this. But if I created Parent object I want to be able to call the parentMethod. Is there some way that I can use to hide this method from being public in Child class, but still allowing parent object to call this method publicly?
Only solution I have come up with so far is making those methods protected and then creating an other class that would extend parent and then have public method for each function that it needs, but that doesn't sound very smart.
Actually, you should ask yourself: why do you need such restriction? You've defined your method as public - thus, you told PHP that it should be visible everywhere. So to prevent child calls you should use private visibility definition.
There is a way to check if call is made from parent class, like:
class ChildClass extends ParentClass {}
class ParentClass
{
public function parentMethod()
{
if(get_class($this) != __CLASS__)
{
throw new LogicException("Somehow due to business logic you're not allowed to call this from childs");
}
}
}
But I would not recommend to do that. Reasons are:
Readability. Your method is just ordinary public method. Looking to it it's impossible to say either you should use it with child calls or not. Thus, to maintain such code you'll need to check that restriction in code. Now imagine that you have ~50 methods like that. And dozen of classes like that.
Possibly, breaking Law of Demeter. Why should parent class be aware of it's childs when using such limitation?
Finally, it's just unexpected behavior. Looking to definition, anybody will see that you're extending one class by another. Thus, by definition all inherit methods with proper visibility must be inherited. And your logic changes that.
You may think about composition, not inheritance. That may be right way to implement your logic (however, I can't tell that for sure since I don't know whole background)
You can rearrange your code by adding a base parent class for both of your mentioned classes. Like so:
class Base {
public function inheritableMethod1() {}
public function inheritableMethod2() {}
}
class Child extends Base {
}
class Parent extends Base {
public function additionalMethod() {}
}
Move all inheritable methods from the Parent class to the Base, and leave there only those which must not be called on Child (the parentMethod in your example).
The base class optionally might be abstract to prevent instantiating it directly.
Check if Abstract Class suits your needs:
PHP: Class Abstraction
class Child extends Parent {
public function parentMethod(
# Code
}
}
Abstract class Parent {
abstract public function parentMethod();
}
I want to implement a hook-system in my simple ORM, in PHP:
class Record {
public function save() {
if (method_exists($this,"before_save")) {
$this->before_save();
}
//...Storing record etc.
}
}
class Payment extends Record {
private function before_save() {
$this->payed_at = time();
}
}
$payment = new Payment();
$payment->save();
This results in a Fatal Error:
Fatal error: Call to private method Payment::before_save() from
context 'Record' in
Makes sense.
I could change the scope to public, but that seems ugly: no-one but Payment has anything to do with before_save(). It is best left private, IMHO.
How can I make Record call a private method on the class inheriting from the Record?
Add a dummy before_save function to your Record class, set its accessibly to protected. Now all classes that inherit from Record will have this function, if they don't overwrite it it will do NOTHING. If they overwrite it, it can implement the desired functionality.
class Record {
public function save() {
$this->before_save();
//...Storing record etc.
}
protected function before_save() {
return;
}
}
class Payment extends Record {
protected function before_save() {
$this->payed_at = time();
}
}
The winning answer doesn't answer the question. The information about "public", "protected", "private", and "final" should be obtainable on any blog or book.
This question asks about how to use a "private" function from an inherit class. The use case here is you're forced to use 3rd party code that is poorly designed, indiscriminately uses private functions, and faced with having to either find a way to use a private function, or fork the entire repo.
Here is the answer to the question.
class foo {
protected $text = "foo";
private function bar($text)
{
return $text.'->'.$this->text;
}
}
class fooChild extends foo{
protected $text = "bar";
public function barChild()
{
$r = new \ReflectionMethod(parent::class, 'bar');
$r->setAccessible(true);
//return $r->invokeArgs(new foo(), ['output']); // output->foo
return $r->invokeArgs($this, ['output']);//output->bar
}
}
echo (new fooChild())->barChild();
Using the ReflectionMethod class you can call a private method from the inherit class. You can see the difference from using $this and a new instance of the parent. The properties will not be set from the child from a new instance.
Check the error message
Call to private method Payment::before_save() from context 'Record'
This means that you are trying to call a function defined in Payment while you are within Record. Class Record does not have a before_save method because it is further up in the inheritance chain than where the function is defined.
In other words since, the parent-child relation is Record (is parent of) Payment, Payment has access to Records functions (by virtue of inheriting from the parent) but not vice-versa (parent cannot "inherit" child class functions). You can make your function protected which will give it access up and down the inheritance chain, but you might want to rethink the architecture and decide if you want it so.. Ideally you should have the function defined in Record and have it overridden in Payment
Also (and I might be wrong with this), but checking explicitly for method_exists is usually not required unless you are creating a really dynamic system where run time classes can be overlapped and/or generated. If you are defining a class based system from ground-up and you know how you are stitching up the various pieces, usually you would not need to check during run-time if method_exists...just a thought..
change the scope to protected:
http://php.net/manual/en/language.oop5.visibility.php
Visibility and the rules of inheritance in PHP:
Members declared protected can be accessed only within the class itself and by inherited and parent classes
class test {
private function pri($val){
return $val;
}
function caller(){
return $this->pri(5);
}
}
$testobj = new test;
echo $testobj->caller();
You will get 5 as output.
By this way You can access the private function of a class.