Extending classes in PHP - strange behaviour - php

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.

Related

Calling a child class function if not exist in parent class

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

Determine the name of the calling class (parent or child) in parent class method

Looking for a clean way to determine the class (in this case, either parent or child class) of the method that calls a method in the parent class.
I thought late static binding could handle this, but seems like that only really works for calling a static method directly, and not from within an instantiated object's method.
Consider the following:
abstract class ParentClass {
public function parentMethod() {
self::_log("parent.non.static");
}
public static function parentStatic() {
self::_log("parent.static");
}
public static function getClassName() {
return __CLASS__;
}
protected static function _log($key) {
$prefix = 'graphite.key.prefix';
$class = static::getClassName(); // gets the object's class, not calling class
$g_key = "{$prefix}.{$class}.{$key}";
echo "{$g_key} \n";
// Graphite::increment($g_key);
}
}
class ChildClass extends ParentClass {
public function childMethod() {
self::_log("child.non.static");
}
public static function childStatic() {
self::_log("child.static");
}
public static function getClassName() {
return __CLASS__;
}
}
$obj = new ChildClass;
$obj->childMethod(); // graphite.key.prefix.ChildClass.child.non.static
$obj->parentMethod(); // graphite.key.prefix.ChildClass.parent.non.static
ParentClass::parentStatic(); // graphite.key.prefix.ParentClass.parent.static
ChildClass::childStatic(); // graphite.key.prefix.ChildClass.child.static
Looking for a clean way to get the class that calls the _log() method without having to pass it in as a parameter. Doesn't have to be static at all, but I was playing around with the late static binding, because I thought that would work, but it just gets the name of the instantiated object, not the child/parent class of the method that calls the _log() method :-/
Edit:
Just to be clear, I'm after getting the class name of the method that called _log() from within the instantiated object (like parentMethod() and childMethod()) Don't care if _log() is static or not. If that makes it easier, fine. But the static ParentClass::parentStatic() and ChildClass::childStatic() were just to show late static bindings and what I figured might work, but not from calling within an instantiated object
http://php.net/manual/en/function.get-called-class.php
class One {
public static function test() {
echo get_called_class() . PHP_EOL;
}
}
class Two extends One {}
One::test();
Two::test();
Output:
One
Two
Also, according to the top comment in the docs static::class also works as of PHP 5.5.
get_class will get the class name of a class instance. This can also be called on $this within a class. If you have a class that extends/implements another, $this will refer the the instantiated class, meaning the child class.
Another option is to use debug_backtrace to get the stack of functions that lead up to where you currently are. You can parse the returned array to get whatever you need including line numbers, classes, functions, methods, whatever.

overriden method getting called twice

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.

PHP Class extending an Abstract cannot run a function that has the same name as the Abstract Class

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

Difference between constructor and unified constructor in php

Is there any difference in constructor or unified constructor. I have a class which have a constructor and a unified constructor. When i intialise object of the class then unified constructor call why not normal constructor.
<?php
class test {
function __construct() {
print "In BaseClass constructor\n";
}
function test() {
echo 'Class loeaded';
}
}
$obj = new test();
?>
OUTPUI
In BaseClass constructor
PHP Version 5.2.6
Since PHP 5, the best way to declare a constructor method in a class is to use the standardized
__construct()
So if you have
class myA {
public function __construct() {
echo "hello construct myA";
}
public function myA() {
echo "hello basic way myA";
}
}
$myA = new myA();
It will echo
hello construct myA
because the __constructor() has priority
But, for compatibility reason, the old way may work if there is not __construct() method.
And:
class myA {
//public function __construct() {
// echo "hello construct A";
//}
public function myA() {
echo "hello basic way myA";
}
}
$myA = new myA();
will give you:
hello basic way myA
In all cases, I advise you to use __construct()
the old constructor (method with class name) is only there for compatibility reasons. so if you have the new constructor (__construct) in the class php won't bother to call the old one.
edit
interesting note is that calling parent::__construct when the class being extended has only the old constructor type will still work (it becomes like a alias to the real constructor)
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.
Read documentation of constructor (link)
Instances of classes are created using the new keyword. What happens during the new call is that a new object is allocated with its own copies of the properties defined in the class you requested, and then the constructor of the object is called in case one was defined. The constructor is a method named __construct(), which is automatically called by the new keyword 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.
In PHP 4, instead of using __construct() as the constructor’s name, you had to define a method with the classes’ names, like C++. This still works with PHP 5, but you should use the new unified constructor naming convention for new applications.
We could pass the names of the people on the new line in the following class example :
class Person {
function __construct($name)
{
$this->name = $name;
}
function getName()
{
return $this->name;
}
private $name;
};
$judy = new Person("Judy") . "\n";
$joe = new Person("Joe") . "\n";
print $judy->getName();
print $joe->getName();
Tip: Because a constructor cannot return a value, the most common practice for raising an error from within the constructor is by throwing an exception.
According to documentation As of PHP 5.3.3, methods with the same name as that of class will no longer be treated as constructor .. They are like regular methods ...
<?php
class myclass
{
public function myclass()
{
// treated as constructor in PHP 5.3.0-5.3.2
// treated as regular method as of PHP 5.3.3
}
}
?>
`
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.
It means that there if you have constructor myclass() and __construct .. then __construct will be searched for first and taken as constructor instead of myclass()
class myclass
{
public function myclass()
{
echo 'hello';
}
function __construct() {
print "new constructor"
}
}
$obj = new myclass(); // will echo new constructor

Categories