I'm having troubles finding a class name after extending other classes. Here are the relevant classes:
class Home extends Controller {
public function test() {
Example::all();
}
}
Class Example extends Active {
//Variables
}
Class Active extends Database {
public function all() {
//This is where I need to store a variable containing the class name Example.
}
}
I'm trying to retrieve the name of the Class Example in Class Active from when it is called from class Home, however I've found it impossible to do this so far without adding an extra argument (which I don't want to do).
You are looking for
get_called_class — the "Late Static Binding" class name
Example (demo)
class Home {
public function test() {
Example::all();
}
}
Class Example extends Active {
//Variables
}
Class Active {
public static function all() {
var_dump( get_called_class() );
}
}
Note that I have changed the signature of Active::all to static because calling non-static methods statically will raise E_STRICT warnings. In general, you want to avoid static methods and Late Static Binding.
have you tried with ReflectionObject class from PHP ? Have a look to this method
Hope this helps
Related
I have following parent and child class.
class Parent_class {
protected static function method_one() {
echo "I am in Parent_class in method_one";
}
protected function execute() {
static::method_one();
}
public function start() {
$this->execute();
}
}
class Child_class extends Parent_class {
protected static function method_one() {
echo "I am in Child_class in method_one";
}
}
$obj = new Child_class();
$obj->start();
Result - it is calling Child class method.
The result is as expected because of static late binding is supported in php5.3 with the already reserved keyword static.
But the issue is, I do not have write access to Parent class, hence I can not use static while calling methode_one and hence it is not performing late static binding.
Is there any way out using which I can access overriding method ?
Parent class is a defined library, and I can not modify it.
Way out is to modify the parent class or drop this thought completely, but can you suggest any other alternative ?
Why not implement execute or start in child class?
In other OO languages like Java we can override a function, possible using keywords/annotations like implements, #override etc.
Is there a way to do so in PHP? I mean, for example:
class myClass {
public static function reImplmentThis() { //this method should be overriden by user
}
}
I want user to implement their own myClass::reImplementThis() method.
How can I do that in PHP? If it is possible, can I make it optional?
I mean, if the user is not implementing the method, can I specify a default method or can I identify that the method is not defined (can I do this using method_exists)?
<?php
abstract class Test
{
abstract protected function test();
protected function anotherTest() {
}
}
class TestTest extends Test
{
protected function test() {
}
}
$test = new TestTest();
?>
This way the class TestTest must override the function test.
Yes, there is. You have the option to override a method by extending the class and defining a method with the same name, function signature and access specifier (either public or protected) it had in the base class. The method should not be declared abstract in the base class or you will be required to implement it in the derived class. In you example it would look something like this:
class MyClass {
public static function reImplmentThis() { //this method should be overriden by user
}
}
class MyDerivedClass extends MyClass {
public static function reImplmentThis() { //the method you want to call
}
}
If the user does not overrides it, MyDerivedClass will still have a reImplmentThis() method, the one inherited from MyClass.
That said, you need to be very careful when invoking extended static methods from your derived class to stay out of trouble. I encourage you to refactor your code to extend instance methods unless you have a very specific need to extend static classes. And if you decide there is no better way than extending static classes please be sure to understand Late Static Binding pretty well.
Yes, its possible to check if the method is implemented or not and get a whole lot more of information about a class using PHP Reflection.
This touches on several OOP subjects.
First, simply overriding an method declared in a parent class is as simple as re-declaring the method in an inheriting class.
E.g:
class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
}
class Tommy extends Person {
public function greet(string $whom = "everyone") {
echo "Howdy $whom! How are you?";
}
}
$a = new Tommy();
$a->greet('World');
// outputs:
// Howdy World! How are you?
If on the overriding method you wan to reuse the logic of the overriden one, it's just a matter of calling the parent's method from the extending class::
class Tommy
{
public function greet(string $whom)
{
// now with more emphasis!!!
echo parent::greet(strtoupper($whom)) . "!!!!";
}
}
Now Tommy::greet() calls Person::greet(), but modifies the result before returning it.
One thing to note is that overriding methods have to be compatible with the overriden one: the method visibility can't be more restrictive than the original one (it's OK to increase visibility), and the number and type of required arguments can't conflict with the original delcaration.
This works, because the type of the arguments does not clash with the original, and we have less required arguments than on the parent:
class Leo extends Person {
public function greet(string $whom = "gorgeous", string $greet = "Whatsup" ) {
echo "$greet $whom. How are you?";
}
}
But this doesn't, since there are additional required arguments. This would make impossible to switch the original class for this one transparently, and thus would throw a Warning:
class BadBob extends Person {
public function greet(string $whom, string $greet ) {
echo "$greet $whom. How are you?";
}
}
Additionally, you mention in your question that "this method should be overriden by the user". If you require client classes to actually implement the method, you have a couple of options:
Abstract classes & methods
These are methods where the implementation is left empty, and that extending classes have to implement to be valid. In we changed our original class Person to:
abstract class Person {
public function greet(string $whom) {
echo "hello $whom!";
}
public abstract function hide();
}
Since now the class contains an abstract method, it needs to be declared as an abstract class as well.
Now it is not possible to instantiate Person directly, you can only extend it in other classes.
Now all our existing Person extending classes would be wrong, and trying to execute the previous code would throw a fatal error.
An example of a valid class extending Person now would be:
class Archie extends Person {
public function hide() {
echo "Hides behind a bush";
}
}
Any class that extends Person must declare a public hide() method.
Interfaces
Finally, you mention interfaces. Interfaces are contracts that implementing classes have to fulfill. They declare a group of public methods without an implementation body.
E.g.:
interface Policeman {
public function arrest(Person $person) : bool;
public function help($what): bool;
}
Now we could have class that extended Person and implemented Policeman:
class Jane extends Person implements Policeman {
public function hide() {
echo "Jane hides in her patrol-car";
}
public function arrest(Person $person): bool{
// implement arrest method
return false;
}
public function shoot($what): bool {
// implements shoot() method
return false;
}
}
Importantly, while it's possible to extend only one class (there is no multiple inheritance in PHP), it is possible to implement multiple interfaces, and the requirements for each of those have to be fulfilled for the class to be valid.
If I have an abstract class like this:
abstract class MyApp
{
public function init()
{
$this->stuff = $this->getStuff();
}
public function getStuff()
{
return new BlueStuff();
}
}
And then I have a class that extends from this abstract class like this:
class MyExtendedClass extends MyApp
{
public function init()
{
parent::init();
}
public function getStuff()
{
return new RedStuff();
}
}
If I do:
$myobj = new MyExtendedClass();
$myobj->init();
Why does the method getStuff from the child class get called? Isn't $this in the context of the abstract class? If so, shouldn't the method of the abstract class get called?
Thanks!
New answer
In PHP you can use subclasses as if all methods in the parent class that don't exist in the subclass have been copied to the subclass. So your example would be the same as:
class MyExtendedClass extends MyApp {
public function init() {
$this->stuff = $this->getStuff();
}
public function getStuff() {
return new RedStuff();
}
}
Just think of the subclass as having all code of the parent class and you're normally all right. There is one exception to this rule: properties. A private property of a class can only be accessed by that class, subclasses can't access the private properties of parent classes. In order to do that you need to change the private property into a protected property.
Original answer
Abstract classes in PHP are just like regular classes with one big difference: they can't get initiated. This means you can't do new AbstractClass();.
Since they work exactly like regular classes for everything else, this also is the case for extending classes. This means that PHP first tries to find the method in the initiated class, and only looks in the abstract classes if it doesn't exist.
So in your example this would mean that the getStuff() method from MyExtendedClass is called. Furthermore, this means you can leave out the init() method in MyExtendedClass.
Having the following class hierarchy:
class TheParent{
public function parse(){
$this->validate();
}
}
class TheChild extends TheParent{
private function validate(){
echo 'Valid!!';
}
}
$child= new TheChild();
$child->parse();
What is the sequence of steps in which this is going to work?
The problem is when I ran that code it gave the following error:
Fatal error: Call to private method TheChild::validate() from context 'TheParent' on line 4
Since TheChild inherits from TheParent shouldn't $this called in parse() be referring to the instance of $child, so validate() will be visible to parse()?
Note:
After doing some research I found that the solution to this problem would either make the validate() function protected according to this comment in the PHP manual, although I don't fully understand why it is working in this case.
The second solution is to create an abstract protected method validate() in the parent and override it in the child (which will be redundant) to the first solution as protected methods of a child can be accessed from the parent?!!
Can someone please explain how the inheritance works in this case?
Other posters already pointed out that the mehods need to be protected in order to access them.
I think you should change one more thing in your code. Your base class parent relies on a method that is defined in a child class. That is bad programming. Change your code like this:
abstract class TheParent{
public function parse(){
$this->validate();
}
abstract function validate();
}
class TheChild extends TheParent{
protected function validate(){
echo 'Valid!!';
}
}
$child= new TheChild();
$child->parse();
creating an abstract function ensures that the child class will definitely have the function validate because all abstract functions of an abstract class must be implemented for inheriting from such a class
Your idea of inheritence is correct, just not the visibility.
Protected can be used by the class and inherited and parent classes, private can only be used in the actual class it was defined.
Private can only be accessed by the class which defines, neither parent nor children classes.
Use protected instead:
class TheParent{
public function parse(){
$this->validate();
}
}
class TheChild extends TheParent{
protected function validate(){
echo 'Valid!!';
}
}
$child= new TheChild();
$child->parse();
FROM PHP DOC
Visibility from other objects
Objects of the same type will have access to each others private and protected members even though they are not the same instances. This is because the implementation specific details are already known when inside those objects.
Private can only be accessed by the class which defines or Same object type Example
class TheChild {
public function parse(TheChild $new) {
$this->validate();
$new->validate(); // <------------ Calling Private Method of $new
}
private function validate() {
echo 'Valid!!';
}
}
$child = new TheChild();
$child->parse(new TheChild());
Output
Valid!!Valid!!
<?php
class MyParent {
public static function tellSomething() {
return __CLASS__;
}
}
class MyChild extends MyParent {
}
echo MyChild::tellSomething();
The code above echos "MyParent". How can i get to name of child class - in this case "MyChild"? If it's possible...
I just simply need to know which child is calling the inherited method.
__CLASS__ is a pseudo-constant, that always refers to the class, where it is defined. With late-static-binding the function get_called_class() were introduced, that resolve the classname during runtime.
class MyParent {
public static function tellSomething() {
return get_called_class();
}
}
class MyChild extends MyParent {
}
echo MyChild::tellSomething();
(as a sidenote: usually methods don't need to know the class on were they are called)
What you are describing is called Late Static Bindings, and it was made available in PHP 5.3.