I've a code snippet
<?php
abstract class Testing{
public abstract function tester();
public function testing(){
$this->tester();
}
}
class Test extends Testing{
public function tester(){
echo 'test';
}
}
$t = new Test();
$t->testing();
I'm supposed to have an output test but the output I'm getting is testtest?
Why tester() being called twice?
A reference link to ideone
PHP scripting language is case - insensitive. (does not apply to variables though)
Since your child class does not have any constructor , the parent class constructor gets fired.
When you do this..
$t = new Test();
The parent class constructor is fired , which is public function testing() , (See the name of the class matches)
From the PHP Docs..
For backwards compatibility, if PHP 5 cannot find a __construct()
function for a given class, and the class did not inherit one from a
parent class, it will search for the old-style constructor function,
by the name of the class.
Related
This question already has an answer here:
Too few arguments to function Db::__construct(), 0 passed in
(1 answer)
Closed 4 years ago.
When I run this, it complains that
Too few arguments to function Base::__construct(), 0 passed in [FileName].php on line 18 and exactly 1 expected
class Base {
protected $var;
public function __construct($var){
$this->var = $var;
}
}
class ChildA extends Base {
public function handle(){
echo $this->var;
}
}
$base = new Base(10);
(new ChildA())->handle();
But as you can see, I have passed:
$base = new Base(10);
Edit: As mentioned in answers and comments, the problem was not in here:
$base = new Base(10);
...but here:
(new ChildA())->handle();
What am I doing wrong? Also, what I am trying to achieve is that, there are many ChildX classes who need to extend Base and all these child classes must have the $var property. So, Instead of duplicating the $var in each child classes, I wanted to reduce typing effort by putting it in a parent class. But apparently, my plan didn't work out.
Your problem is actually this line:
(new ChildA())->handle();
Do this instead:
$child = new ChildA(10);
$child->handle();
You don't need to instantiate the base class separately.
One other thing. When both parent and child classes have a constructor, you can put parent::__construct($whatever); in the child's constructor to run the parent code also.
This is a simple concept of class instantiation, I think which you are getting it wrong.
When you did
$base = new Base(10);
you are creating an instance of the Base class only.
However, the following statement invokes another instance of the Child class. Note, the base variable and this child instance are two different entities, hence their behaviour will not impact each other.
(new ChildA())->handle();
So, currently base variable will have a value of 10, but the handle() function call cannot be instantiated since it requires an argument which is to be supplied to the new instance of the Base class.
You'll need to instantiate the child class, due to which the constructor of the inherited class will be called first and your variable will be set. Your handle() function can then successfully return the correct value.
$child = new Child(10); $child->handle(); //returns 10
When you extend a class, all the methods on that class exist on the child class by default, including "magic" methods like __construct.
So when you write this:
class Base {
protected $var;
public function __construct($var){
$this->var = $var;
}
}
class ChildA extends Base {
public function handle(){
echo $this->var;
}
}
Your child class actually looks something like this:
class ChildA extends Base {
// Inherited property from Base class
protected $var;
// Inherited method from Base class
public function __construct($var){
$this->var = $var;
}
// New method in this class
public function handle(){
echo $this->var;
}
}
This is a slight simplification, as we'll see below, but it explains what happens in your example:
$base = new Base(10);
$base is an instance of the Base class; it is completely separate from any other instance of that class, and from any instance of the ChildA class.
(new ChildA())->handle();
This attempts to run the __construct method in the ChildA class; the copy of that method inherited from Base requires an argument, but you didn't supply one, so you get an error. It is expecting you to call it like this:
(new ChildA(10))->handle();
If we define __construct directly in the child class, we can give it a different number of arguments:
class ChildB extends Base {
public function __construct() {
// Do nothing
}
public function handle(){
echo $this->var;
}
}
(new ChildB())->handle();
But now we have a different problem: the logic in the Base class isn't running, so $this->var is never set to anything.
This is where I over-simplified things above. In reality, the parent __construct method and child __construct method both exist, they just "hide" each other. You can access the parent copy with the syntax parent::method.
So you can make a child class, with a constructor which takes no arguments, and when that constructor is run, run the base constructor with a hard-coded value of 10:
class ChildC extends Base {
public function __construct() {
// Run the constructor in the Base class
parent::__construct(10);
}
public function handle(){
echo $this->var;
}
}
(new ChildC())->handle();
Your new ChildA() is calling constructor from Base and you are not passing any arguments here.
You make mistake here: when you do new Base(10) your $var is not passed to new instance of new ChildA()
In your case I would use static parameter instead of constructor value
class Base {
protected static $var;
public function __construct(){
}
public static function setVar($var) {
self::$var = $var;
}
}
class ChildA extends Base {
public function handle(){
echo self::$var;
}
}
Base::setVar(10);
(new ChildA())->handle();
I have a code like following ---
class CartItem{
var $v;
function __construct(){
$this->f();
}
function f(){
echo 'In parent';
}
}
class m extends CartItem{
function f(){
echo 'In child';
}
}
new m();
Now when creating instance of m()... it doesn't have any constructor, so it is calling parent classes constructor. Now inside that a function f is called.
What I want is -
if class m() have defined function f()... is should call it instead of parent class's function f().
But anyway it is calling parent classes function, as it was called from parent's constructor, irrespective of child class/ context :(
You want to call in __construct() a method that is not defined in the class. This is a sign that the CartItem class is an abstract concept and you don't intend to instantiate it (because an instance of CartItem probably doesn't contain enough information or behaviour for your project).
An abstract concept is implemented using an abstract class that defines as much as it can and defines abstract methods to be implemented in the concrete classes that extend it. The method f() is such a method that cannot be defined in the abstract concept and has to be defined in each class that extend it:
abstract class CartItem
{
public function __construct()
{
$this->f();
}
abstract protected function f();
}
class m extends CartItem
{
protected function f()
{
// Implement behaviour specific to this class
}
}
This is actually a really interesting question.
so, as I understand it, you're asking (if this isnt right please say):
can you call a function of a class that's extending a parent?
yes, you can... sort of, if the method in the child is static.
Take this example (Ive not used it in the constructor for simplicity of example, but it will work there too):
class ClassA {
public function testMeAsWell() {
return ClassB::testMe();
}
}
class ClassB extends ClassA {
static function testMe() {
return 'do something';
}
}
$child = new ClassB();
echo $child->testMe();
// outputs 'do something'
$parent = new ClassA();
echo $parent->testMeAsWell();
// also outputs 'do something'
the reason this works needs more research, but as a guess I would say that because PHP is compiled, it will know about both classes at run-time and therefore will be able to figure out what we wanted it to do.
So, further on, you want to use variables. Yes you can, but they would have to be static as well.
working example
First, quote from PHP manual (http://php.net/manual/en/keyword.extends.php):
The extended or derived class has all variables and functions of the
base class (this is called 'inheritance' despite the fact that nobody
died) and what you add in the extended definition.
So why is that this simple example doesn't work:
<?php
class A
{
private function a()
{
echo 'a';
}
public function b()
{
echo 'b';
}
}
class B extends A
{
//no extended definition, only what's inherited
}
$object_B = new B();
echo $object_B->b(); // fatal error: Call to private A::a() from invalid context
?>
After some experimenting, it turns out that removing method a from class A
makes it work. And I'm not even calling it anywhere.
You can use a method of the same name as a constructor with a PHP class. So, your method a is acting as a constructor for class A.
Rename your method, and it should work:
class First
{
private function another()
{
echo 'a';
}
public function b()
{
echo 'b';
}
}
See __construct() vs SameAsClassName() for constructor in PHP
"Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP" - Reports PHP 7 after executing the sample code.
I think you can't name the method with the same name as the class. In older PHP-Versions you could define the constructor of the class by naming the method like the class. PHP assumes the functions a to be a constructor. So it won't work that way.
Like Zac Brown said, you have to use the __construct() method.
In class A you have define a() method it with same name of class. so it is constructor method of A class. but in PHP you can not make private constructor method. your code should be like this.
<?php
class A
{
public function a()
{
echo 'a';
}
public function b()
{
echo 'b';
}
}
class B extends A
{
//no extended definition, only what's inherited
}
$object_B = new B();
echo $object_B->b();
Here's the clarification:
You are defining method a() in Class A. They have the same name so method a() is treated as constructor of Class A. Therefore, the moment you initialize Class B in $object_B = new B();, you initialize Class A too since A is extending B and the constructor method is called. Because Classes which have a constructor method call this method on each newly-created object PHP Constructor. and hence the error.
I believe this clarifies your doubt.
I was playing around with a couple of classes to understand the relationship between parent and child. I setup the parent to have a constructor that calls an init method. Then when I add an init method to the child, it should override the parent init, shouldn't it? But what is happening is that both methods are being called.
To test this, I wrote a class named Model and a child called Instance. Here is the code:
$try = new Instance;
echo $try;
class Model{
public function __construct(){
$this->init();
}
public function init()
{
return $this->className();
}
public function __toString()
{
return $this->className();
}
public static function className()
{
return get_called_class();
}
}
class Instance extends Model
{
public function init()
{
echo "tada! ";
}
}
Gives the following output:
tada! Instance.
In class Model, I use the magic method __toString() to return the class name as a string. The constructor of the parent calls the parent init() method, which in this case echoes the class name.
My understanding is that if I write a child class, in this case the class is called Instance, with an init() method, it would overwrite the parent init() method, but that is not what is happening. In this case, it returns both init mehtods and I have no idea why. Can anyone explain this?
The fact is -
When you instantiate an object of Class "Instance" using "$try = new Instance;". it calls the constructor and since child class overrides "init" method, it prints "tada!".
On the other line you echo the object of Class "Instance" using "echo $try;" and a magic method __toString() implemented in parent class. So it print "Instance" as class name.
You can run only $try = new Instance; that will print only "tada!".
You are running two different commands. First you are instantiating the class with $try = new Instance; which is calling __construct. The __construct() in the parent class is calling init() which is using the child init() and returning tada!. Create a blank constructor in the child class to override the parent constructor.
The second command is when you echo the class: echo $try; using __toString() which is echoing Instance as defined in the parent class.
You can also add to a parent constructor by using:
public function __construct() {
...code...
parent::__construct();
...code...
}
Reason :
Since you don't have any constructor defined for your child class, the parent class constructor will be fired and that is why you get that output.
Explanation :
When you do
$try = new Instance;
The parent class constructor gets fired and it will call the init() which in turn calls the className() that does the get_called_class() , so eventually your init() in the child class will be called and you get the output "tada!" first.
And when you do..
echo $try;
The __toString() is called and returns you the class name Instance
So basically , If you had a constructor on your child class , you will not be getting the output "tada!"
In this case, it returns both init mehtods
No it doesn't;
'tada!' is being echoed by Instance::init() and 'Instance' is being echoed by Model::__toString().
This code fails. But I don't understand why. If I change the function lol to function anything else, it works. If I change the class of the Abstract it also works. See this execution: http://codepad.viper-7.com/Z9V67x
<?php
abstract class Lol{
abstract public function lol($external = false);
}
class Crazy extends Lol{
public function lol($external = false){
echo 'lol';
}
}
$new = new Crazy;
$new->lol('fdgdfg');
The error that comes back is:
Fatal error: Cannot call abstract method Lol::lol() in /code/Z9V67x on line 17
PHP Fatal error: Cannot call abstract method Lol::lol() in /code/Z9V67x on line 17
Doing some research on same name functions and classes, in PHP4 the same name meant a constructor. According to this https://stackoverflow.com/a/6872939/582917 answer, namespaced classes no longer treated functions with the same name as the constructor. BUt non namespaced classes do. Still why can't the constructors be replaced in the child instance?
check code below:
abstract class Lol{
public function __construct() { // only one constructor is really needed
}
abstract public function lol($external = false);
}
class Crazy extends Lol{
public function __construct() { // only one constructor is really needed
}
public function Crazy() { // only one constructor is really needed
}
public function lol($external = false) {
echo 'lol';
}
}
$new = new Crazy();
$new->lol('fdgdfg');
it works ok, why?
PHP is not very good with OOP, even latest version, it has PHP4 legacy, so lets try to understand what your code do:
it defined abstract function, which is understand by php as constructor and as abstract method
in sub class you're defining only method, but constructor is still abstract
this is why you're getting error during new - php really cannot find constructor
now check code above - it has 3 constructors, you can have any 1 and this code will work