I have 3 classes with the following inheritance structure:
<?php
class admin {
function __construct($module){
echo $module;
}
}
class user_admin extends admin {
function __construct(){
parent::__construct('user');
}
}
class sales_admin extends user_admin {
function __construct(){
parent::__construct('sales');
}
}
You'll notice that the sales_admin extends the user_admin, this is a nescessary step. When I run this code,
$a = new sales_admin;
it will echo "user", because it passes the "sales" string to the user_admin which doesn't accept a constructor.
Is there a way to access the constructor of the parent above it without changing the user_admin, which I don't have control over?
Just reference the class directly:
class sales_admin extends user_admin
{
function __construct()
{
admin::__construct('sales');
}
}
$a = new sales_admin; // outputs 'sales'
Since user_admin extends admin, and sales_admin extends user_admin, sales_admin will have scope of the admin constructor
//super implimentation php
class object extends other_object {
function __construct(){
$this->super();
}
function super() {
$parentClass = get_parent_class($this);
$this->$parentClass();
}
}
sales_admin knows it has a parent because it is extending user_admin. However, how can sales_admin possibly know if user_admin has a parent? In PHP, sales_admin does not have a way of knowing -- unless you cheat with reflection.
An option that you do have is to borrow admin's constructor. You can do this by calling admin::__construct('sales');. Note that you can borrow the method of any class this way, regardless of the inheritance tree -- that is, the caller does not have to be a descendant of the callee.
Despite this option, I would recommend changing your design in such a way that you can avoid the inheritance altogether.
Related
I sometimes find myself performing a similar task on various different related things. For instance, I might have "books", "movies", and "songs", and I might have the task "addNote" which gets the note text from the client, adds it to a database, associates it with the appropriate parent record, and returns some data to the client. I've implemented it as shown below, and while it works, it just seems wrong. Is there a better way to do this, and if so how? Thanks
class parentClass
{
protected function someTask($table)
{
//do the task which is common to child1/2/3Class using $table
}
}
class child1Class extends parentClass
{
public function someTask($dummy=NULL){parent::someTask('class1_table');}
}
class child2Class extends parentClass
{
public function someTask($dummy=NULL){parent::someTask('class2_table');}
}
class child3Class extends parentClass
{
public function someTask($dummy=NULL){parent::someTask('class3_table');}
}
$ajax=new child1Class(); //specific childClass based on MVC
$ajax->someTask();
The way you have it is correct. The only other option you have is making the parent method "public"
class parentClass
{
public function someTask($table)
{
echo "hello " . $table;
}
}
class child1Class extends parentClass
{
// no needed method here
}
class child2Class extends parentClass
{
// no needed method here
}
$obj1 = new child1Class();
$obj1->someTask('class1_table');
$obj2 = new child1Class();
$obj2->someTask('class2_table');
$obj3 = new child2Class();
$obj3->someTask('class3_table');
result with obj1: "hello class1_table"
result with obj2: "hello class2_table"
result with obj3: "hello class3_table"
Public makes the method directly accessible through the object.
Protected makes the method accessible through the child class
Private makes the method only accessible through its own class.
I have a parent class that has a public function that is final. Is it possible to disallow access to this method in a derived class? Other classes that derive from the parent class need to still be able to call it.
class ParentClass {
final public function test() {
}
}
class ChildClass extends ParentClass {
}
class ChildClass2 extends ParentClass {
}
$child = new ChildClass();
$child2 = new ChildClass2();
// make this illegal:
$child->test();
// but not this:
$child2->test();
When you inherit from class it means that derived class is a class that inherits. It means that it has exact the same base functionality that can be expanded, overriden and so on. If it makes no sense that derived class had method that is defined in parent class means that derived class is not a class that it derives.
For real world example let's say you have class FlyingMachine that has method Fly and Move, it would not be logical if you derived class Car from FlyingMachine because cars don't fly, while deriving class AirPlane from mentioned base class is perfectly fine. But it would be logical if you had base class Machine that had method Move and car was derived from this class Car : Machine (car is a machine, right?), FlyingMachine is a machine too so FlyingMachine : Machine is perfectly fine and since air-plane is a flying machine AirPlane : FlyingMachine makes sense.
For your given example this should be something like:
abstract class VeryBaseClass {
public function MethodThatIsLogicalForEveryDerivedClass() {}
}
abstract class BaseClass extends VeryBaseClass {
public function SomeOtherFunctionThatMakesSenseOnlyForSomeClasses() {}
}
class ClassThatShouldNotHaveSpecificFunctionDefinedInBaseClass extends VeryBaseClass{}
class ClassThatShouldHaveSomeOtherMethod extends BaseClass {}
Edit:
If there's a functionality that several derived classes need but for some of them it should be public and for some of them not. You should define in base class this method as protected (derived class can access one but from outside impossible). And in derived class that require that this method was public make another method and call parent's method. E.g.:
abstract class Car { protected function Shift() {} }
class ManualCar extends Car {
public function Shift() { parent::Shift(); }
}
class AutomaticCar extends Car {
//Some implementation of automatic car that uses protected Shift method
}
Little demo
How about checking for that class in the method, and throwing an exception if it's the disallowed class:
class ParentClass {
final public function test() {
if (get_class($this) == "ChildClass")
throw new Exception("ChildClass cannot call test()")
}
}
NB: this is fairly evil
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.
I would have thought lots of people would have wondered whether this is possible but I can't find any duplicate questions... do correct me.
I just want to know whether PHP offers pure virtual functions. I want the following
class Parent {
// no implementation given
public function foo() {
// nothing
}
}
class Child extends Parent {
public function foo() {
// implementation of foo goes here
}
}
Thanks very much.
You can create abstract functions, but you need to declare the parent class as abstract, too:
abstract class Parent {
// no implementation given
abstract public function foo();
}
class Child extends Parent {
public function foo() {
// implementation of foo goes here
}
}
Declare the method as abstract in the Parent class:
abstract public function foo();
There are abstract classes!
abstract class Parent {
// no implementation given
abstract public function foo();
}
}
class Child extends Parent {
public function foo() {
// implementation of foo goes here
}
}
Yes, that type of solution is possible, it's called polymorphism, you can do it without declaring an abstract class or an interface.
In the project my team is currently working on, we're modifying a commercial PHP application. The app is strewn with code where a parent class checks for and works with a property that doesn't exist in the parent class, like so:
class A
{
function doSomething()
{
if (property_exists($this, 'some_property'))
{
$this->some_property = $_REQUEST['val'];
}
}
}
class B extends A
{
protected $some_property;
function doSomething()
{
parent::doSomething();
}
}
We feel vaguely dirty having to modify this code; is this proper design? What are the ways (other than the obvious) something like this can be avoided?
You might consider abstracting the parent class. So the methods that the children must have are declared in the parent, but not implemented.
Relying upon methods that must exist in a subclass is not dirty, as long as you can declare them as abstract.
However, it is not good practice to rely on and manipulate properties outside of a class. It's best to use abstract setters, like this:
abstract class A
{
abstract protected function setSomeProperty($data);
public function doSomething()
{
$this->setSomeProperty($_REQUEST['val']);
}
}
class B extends A
{
private $some_property;
public function doSomething()
{
parent::doSomething();
}
protected function setSomeProperty($data)
{
$this->some_property = $data;
}
}
More info here: PHP Class Abstraction
However, since you said you're not allowed to modify the parent class, I would suggest making a subclass that acts as an Adapter to what the parent class "expects", and a class that you're able to design "properly".
You can create a virtual method hook in the parent class which can later be overridden by children.
I think it's more neat to create a sub-class, where all members have function doSomething(). In that case you don't create a not-working function in a parent class (with eventual hacks), but still have the general "super-function".
class A
{
}
class C extends A {
protected $some_property;
function doSomething()
{
$this->some_property = $_REQUEST['val'];
}
}
class B extends C
{
protected $some_property;
function doSomething()
{
parent::doSomething();
}
}