What is the PHP way to do a correct override ?
php -a
Interactive mode enabled
php > error_reporting(E_ALL);
php > class A { public function z($a, $b){} }
php > class B extends A { public function z($a){parent::z($a, '1');} }
PHP Strict standards: Declaration of B::z() should be compatible with A::z($a, $b) in php shell code on line 1
Note: Override is the correct word in english ?
In your example, in class A function z have 2 parameters, in class B you are trying to declare it with 1 parameter. In php it wont work.
Btw. I guess you probably want to OVERLOAD funciotn z not override it, and it is not really supported in php. If I'm right here is little explanation fro manual:
Note:
PHP's interpretation of "overloading" is different than most object oriented languages. Overloading traditionally provides the ability to have multiple methods with the same name but different quantities and types of arguments.
The reason for the E_STRICT notice (which is just a programming hint, not an error as such) is that a child class should theoretically be usable interchangeably with its parent (the posh term is the "Liskov Substitution Principle").
In your case, you need to know that you have an instance of B in order to leave off the second parameter. PHP is being relaxed and letting you do it, but it's not really how inheritance should work - B extends A should mean that everything that "is a B" also "is an A".
If you used an interface to define the contract for function z($a, $b), class B would violate that contract.
A better approach for this problem would be to use delegation rather than inheritance: class B could act as an "adaptor" which uses A's behaviour, but simplifies it, e.g.
class B
{
private $delegated_a;
public function __construct() {
$this->delegated_a = new A;
}
public function z($a) {
$this->delegated_a->z($a, '1');
}
}
Here, we're making no promise to calling code about the relationship between A and B, so can re-define the methods however we like.
You mean method overloading :)
Well actually this works a bit different then you would expect if you programmed in Java before. Please also checkout the comment in the PHP manual.
The difference is that in eg. Java you can have multiple methods with the same name but another footprint. Eg:
public void max(int a, int b) {
// calculate max value
}
public void max(double a, double b, double c) {
// do some other calculation
}
Now if you would call the method max, Java will automatically decide which method to use.
Now in PHP this does not work. You can overwrite a method in a child class, but only if the footprint is the same, and you can only define the method in the child class. Example:
class A {
function z($a, $b) {
echo 'called in A';
}
}
class B extends A {
function z($a, $b) {
echo 'called in B';
}
}
$a = new A;
$b = new B;
$a->z(1, 2); // prints out "called in A"
$b->z(1, 2); // prints out "called in B"
Related
I'm used to put method as protected in my PHP classes. But playing with private I'm starting to have doubts.
I know that it might be a duplicate but I can't find clarity from the SO-answers I've read.
Checked the documentation and SO answers but still my tests are incoherent with what is being said there (see below).
Especially is not often explained the kind of "tangling" among public and private method, when extending the same type class, in the context of PHP.
For example:
<?php
class A
{
private function ab() { echo 'test'.PHP_EOL; }
public function test() { $this->ab(); }
public function accessprivate($obj) { $obj->ab(); }
}
class B extends A
{
public function ab() { echo 'overridden-public'.PHP_EOL; } // expect notice overriding private parent method
}
$a = new A;
$a2 = new A;
$b = new B;
$a->test(); // expect 'test'
$b->test(); // expect access to B::ab() and print 'overridden-public'
$b->ab(); // expect access to B::ab() and print 'overridden-public'
$a2->accessprivate($a); // expect 'test' since is the same class
$b->accessprivate($a); // expect cannotaccess private of A from class B
When running this is the result:
test test overridden-public test test
The main point is that I expected that a private method is inherited but not accessible to child classes; hence:
I shouldn't be able to change the visibility of ab() to public
with the override of ab() in B I would expect test() to call ab() on $this as B instance, and get printed "overridden-public"
accessprivate() from $a2 on $a is fine because they are the same class
accessprivate() from $b on $a should NOT be fine because they are different classes (parent & child)
So the questions are:
Why am I wrong? What am I misunderstanding?
Is this visibility model the same on other languages or PHP is doing it differently? And in that case, are my expectation fitting more the visibility model of some other language?
I shouldn't be able to change the visibility of ab() to public
An overriding implementation must have the same or higher visibility in order to not violate the LSP. The overriding implementation doesn't expose the parent implementation, so no fundamental concern here. If the parent's implementation is non-public, for all intents and purposes it doesn't exist. For all intents and purposes the child is adding a new method to the class, which is fine.
with the override of ab() in B I would expect test() to call ab() on $this as B instance, and get printed "overridden-public"
private methods are "hard bound" to the declaring class. A::test will call a private A::ab preferably. This is specifically so class internals can remain private. Should an extending class implement an identical method unknowingly, there's no surprising behaviour within A.
accessprivate() from $b on $a should NOT be fine because they are different classes (parent & child)
It's still calling A::accessprivate since B doesn't implement any such method, which rather works the same as the test method and the explanation in the previous paragraph.
The purpose of private is largely to guarantee no interference from outside or extending code. If you're marking methods as private, you can be very sure which implementation of code will be called (always the declaring class), regardless of whether methods are overridden in children. If you keep this in mind, the behaviour is pretty expected and self-explanatory. protected methods explicitly allow and expect overriding to take place and behave accordingly.
I was wondering is it bad practice (I'm assuming it is) to do something like this, in PHP? Common sense tells me this could lead to UB, but I haven't been able to find a reference to this in the manual, or elsewhere.
<?php
class A
{
public function __construct(){}
}
class B extends A
{
public function __construct()
{
global $d;
$d = new C; // How wrong is it to replace the value of $d from inside B, like this?
exit();
}
}
class C extends A
{
public function __construct()
{
echo 'C';
}
}
$d = new B;
Output: C
I'd like to know the risks (if any) that come with executing code like this, and would especially appreciate a link to the manual that talks about doing something like this.
Or (since this simple code runs without errors), is this code valid, but just considered a bad practice?
Yes.
This is wrong at multiple levels.
you should not use a global state anywhere in your classes (that pertains both to global variables and singletons/registries).
you should not echo in from within a class's method and especially not from within a constructor
you should not call exit unless in context of "poor man's debugging".
you should not create new instance of a different class inside a constructor, because it becomes extremely hard to test and debug
you should not abuse the extends keyword, because it is meant for creating a specialized subtypes of the base class
If you are expecting that variable $d will contain an instance of class C, you would be wrong.
To find out, remove the exit() and dump $d at the end of your code with print_r() or var_dump().
// your code here without the exit()
echo "\n";
print_r($d);
Here is the entire output:
C
B Object
(
)
Is this a suprise?
Actually, it shouldn't be.
Modifying $d inside the constructor of class B is pointless because when the constructor returns,
whatever value in $d will be overwritten by a new instance of class B.
There is nothing about this is undefined behavior.
Just pointless because it achieves nothing.
What happens if I use a class in two different traits, and both have a method with the same name but different implementations of this method?
Short answer
(c) AbraCadaver
Long answer
Say you have a class Foo that uses traits A and B:
class Foo {
use A, B;
}
Where both traits have a method with a similar name, but different implementation (the implementation doesn't matter, really):
trait A {
public function bar() {
return true;
}
}
trait B {
public function bar() {
return false;
}
Traits work by extending the class horizontally. Simply put - just adding any new contents to the class. And all works fine till there's any doubling in trait methods and properties. Then you have yourself a fatal error if this conflict is not explicitly resolved.
The sweet part is, you can resolve this conflict by specifying which method from which trait to use:
class Foo {
use A, B {
B::bar insteadof A;
}
}
You can also save the other method from oblivion by using alias for it:
class Foo {
use A, B {
B::bar insteadof A;
A::bar as barOfA;
}
}
The manual has traits farely well documented, go check it out.
Just wondering is it best to define an empty constructor or leave the constructor definition out completely in PHP? I have a habit of defining constructors with just return true;, even if I don't need the constructor to do anything - just for completion reasons.
If you don't need a constructor it's best to leave it out, no need to write more code. When you DO write it, leave it empty... returning true doesn't have a purpose.
There is a difference between the two: If you write an empty __construct() function, you overwrite any inherited __construct() from a parent class.
So if you don't need it and you do not want to overwrite the parent constructor explicitly, don't write it at all.
EDIT:
previous answer is no longer valid, since PHP now behaves like other oop programming languages.
constructors aren't part of interfaces. therefore you are now allowed to override them how you prefer without any issues whatsoever
the only exception to this is:
interface iTest
{
function __construct(A $a, B $b, Array $c);
}
class Test implements iTest
{
function __construct(A $a, B $b, Array $c){}
// in this case the constructor must be compatible with the one specified in the interface
// this is something that php allows but that should never be used
// in fact as i stated earlier, constructors must not be part of interfaces
}
PREVIOUS OLD NOT-VALID-ANYMORE ANSWER:
there is an important difference between an empty constructor and no constructor at all
class A{}
class B extends A{
function __construct(ArrayObject $a, DOMDocument $b){}
}
VS
class A{
function __construct(){}
}
class B extends A{
function __construct(ArrayObject $a, DOMDocument $b){}
}
// error B::__construct should be compatible with A constructor
You should only define an empty constructor if your object should never be instantiated. If that is the case, make the __construct() private.
constructor always return instance of class in which its defined . Hence you never use "return" inside constructor . Lastly its better not to define it if you are not gona use it .
One reason you might want to define an empty constructor is when you want to avoid calling a function that has the same class name.
class FooBar {
function foobar() {
echo "Hello world";
}
}
new FooBar(); // outputs "Hello world" in PHP < 8
This is due PHP 4 backwards compatibility, where constructors had the same name of the class.
Anyway it got deprecated in PHP 7.4.26.
class FooBar {
function __construct() {
}
function foobar() {
echo "Hello world";
}
}
new FooBar(); // no output
I'm dumbfounded. I've been looking for a nice definition as to what a class constructor(specifically in PHP) exactly does.
As I understand it, it's the initial function that the class executes, when called, correct?
It is called whether or not we specifically call the function itself?
Can anyone shed some light here? Or at least point me in the right direction.
PHP allows developers to declare constructor methods for classes. Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.
A constructor creates an Object of the class that it is in by initializing all the instance variables and creating a place in memory to hold the Object.
For example you may want to initialize
an integer variable to 10 or 20 based
on a certain condition, when your
class is created. In such a case you
cannot hard code the value during
variable declaration. such kind of
code can be placed inside the
constructor so that the initialization
would happen when the class is
instantiated.
When a PHP class is first called, the class will automatically run the class constructor function, which can help automatically configure the class. This can be useful if you need to preset some instance variables, sessions or cookies – prior to using the class methods.
A good read on Constructors in PHP
You're more or less correct - it is a function that is called when the class is instantiated (created with the new keyword).
You shouldn't have to specifically call it unless you extend a class and override the constructor, because a subclasses __construct() doesn't call it's parent constructor unless explicitly defined with parent::__construct().
E.g.
class A {
public $value;
function __construct() {
$this->value = "A";
}
}
$a = new A();
echo $a->value; // "A";
class B extends A {
}
$b = new B();
echo $b->value; // "A";
class C extends A {
function __construct() {
$this->value = "C";
}
}
$c = new C();
echo $c->value; // "C";
class D extends A {
function __construct() {
$this->value = "D";
parent::__construct();
}
}
$d = new D();
echo $d->value; // "D";
A constructor is called whenever a new instance (i.e. object) of a class is created. This allows you to setup the state of the object, as well as pass in any dependencies that the object might need to work properly, such as a CacheManager, or a database connection, or...
If you have an inheritance chain, i.e. Class C extends Class B which extends Class A, then remember to explicitly call the parent constructor if you override the constructor somewhere further down the chain:
<?php
class C extends B
{
public function __construct ($constructorParams)
{
parent::__construct($constructorParams);
}
}
The constructor should NOT return a value.
As I understand it, it's the initial function that the class executes, when called, correct?
It's the method called when a new instance of the class is first created. It's an instance method, because it only works on instances. (An object is an instance; a class is
something to which an object belongs. It's possible to have methods belong to the class, not to an instance. PHP calls these static methods, but that isn't always the terminology other languages use.)
In some languages, the constructor actually returns the new object. This is not the case in PHP, where the constructor exists for initialization purposes.
It is called whether or not we specifically call the function itself?
Correct. It's called when you use the new operator.
class Foo {
public function __construct() { echo "I foo'd.\n" ;}
}
$f = new Foo(); // Echos "I foo'd.\n"
You probably want to read over the PHP manual sections about classes and objects.
No.
No.
Yes.
Constructor is only called when you create a object. It is not called when you later only use your object somewhere.
When you create a new object, a constructor is a method that is called and it initialize the variables/fields of an object.
A constructor must have the same name as the class its in.
Yes. From Wikipedia -
In PHP (version 5 and above), the constructor is a method named __construct(), which the keyword new automatically calls after creating the object. It is usually used to automatically perform various initializations such as property initializations. Constructors can also accept arguments, in which case, when the new statement is written,you also need to send the constructor the function parameters in between the parentheses.
Wikipedia PHP Constructor Definition
PHP Site: What Constructors do ?
It's called when you create a new instance of the class, which is called automatically and you can initiate any local variables there. To do works which has to be done before freeing / destroying your object you can use the Destructor. Constructors and Destructors are'nt PHP specific but general for OO Programming languages.
See this
#include<iostream>
using namespace std;
class shape{
protected:
int w, h, a;
public:
shape(int, int);
};
shape :: shape(int x, int y){
w = x;
h = y;
};
class triangle : public shape{
public:
void disp_area();
};
void triangle :: disp_area(){
a = (w + h) * 1 / 2;
cout<<endl<<" Area Of Triangle : "<<a;
};
class rectangle : public shape{
public:
void disp_area();
};
void rectangle :: disp_area(){
a = w * h;
cout<<endl<<" Area Of Rectangle : "<<a;
};
int main(){
triangle obj1;
rectangle obj2;
obj1.shape(2, 3);
obj2.shape(4, 5);
obj1.disp_area();
obj2.disp_area();
return 0;
};