How does 'self' exactly work in inherited classes? - php

According to php, class::self always points to the class itself, but as I wrote down these codes, something strange happens:
class C_foo{
function foo() { return "foo() from C_foo"; }
function bar() { echo self::foo(); }
}
class C_bar extends C_foo{
function foo() { return "foo() from C_bar"; }
}
C_foo::bar();
C_bar::bar();
I thought the output would have been:
foo() from C_foo
foo() from C_bar
But in fact:
foo() from C_foo
foo() from C_foo
It means that the self in parent class does NOT exactly inherit into the child, it works more like to this:
foo() {return parent::foo();}
Is that a feature from php or is it a bug? Or is it mean to be like this?
Otherwise, such thing is occurred as I tried to tell a class create objects from itself, the code is something like this:
class Models {
function find($exp) {
...
...
$temp_model = new self();
...
...
}
}
class Something extends Models {...}
$somethings = Something::find("...");
Maybe someone would ask, "why don't you set a variable with the value of class, and use the variable as the __construction function?"
Like this:
...
...
function find($exp) {
...
...
$class_name = __class__;
$temp_model = new $class_name();
...
...
}
...
In fact I did that, and got a even more weird result:
It works only when the class does not have any property or function but find(), or an error telling me a variable shows off where a function sould exist would jump out.

It sounds like you're describing the PHP feature known as 'late static binding'.
PHP provides two syntaxes: self:: and static::.
static was introduced in PHP 5.3 because a lot of people expected self to work the you're describing.
See the PHP manual for more: http://php.net/manual/en/language.oop5.late-static-bindings.php
You can also use the syntax new self() or new static() to create new instances:
$parent = new self();
$child = new static();

This is because the class which receives the methods of the parent is of that class. So:
$bar is Bar, therefore self:: refers to Bar, not to Foo. Even though that method is from Foo.
This may be different from Java, but it probably indicates how PHP is doing inheritance internally.

In PHP, classes are not object. Because of that, there is no inheritance of static methods (actually, they are similar to global functions).
So, when C_foo says self, it always means C_foo (even if you called a method from C_bar).
If you want create instances from an abstract class method, you should try the Factory pattern.

Related

Odd Inheritence PHP issue

Appologies if this is a duplicate, could not seem to either search for the right words or does not exist (somehow i doubt this and likely i am making an obvious mistake).
<?php
class Test {
public $var = true;
public function test() {
var_dump($this->var);
}
}
class Testing extends Test {
public $var = false;
}
$test = new Testing();
$test->test();
Simple enough program, base class, with a method, inheriting class with an override, then calling the base method.
Gives output, False, line return False,
What? Why twice? Exactly my question good man.
bool(false)
bool(false)
Thanks
This happened because your method name same with class name.
Methods like this been used as a class constructor in PHP4 - php.net
They still works, when you have not __construct method for compatibility.

Static methods in PHP

Why in PHP you can access static method via instance of some class but not only via type name?
UPDATE: I'm .net developer but i work with php developers too. Recently i've found this moment about static methods called from instance and can't understand why it can be usefull.
EXAMPLE:
class Foo
{
public static Bar()
{
}
}
We can accept method like this:
var $foo = new Foo();
$foo.Bar(); // ??????
In PHP
the class is instantiated using the new keyword for example;
$MyClass = new MyClass();
and the static method or properties can be accessed by using either scope resolution operator or object reference operator. For example, if the class MyClass contains the static method Foo() then you can access it by either way.
$MyClass->Foo();
Or
MyClass::Foo()
The only rule is that static methods or properties are out of object context. For example, you cannot use $this inside of a static method.
Class Do {
static public function test() {
return 0;
}
}
use like this :
echo Do::test();
Why in PHP you can access static method via instance of some class but not only via type name?
Unlike what you are probably used to with .NET, PHP has dynamic types. Consider:
class Foo
{
static public function staticMethod() { }
}
class Bar
{
static public function staticMethod() { }
}
function doSomething($obj)
{
// What type is $obj? We don't care.
$obj->staticMethod();
}
doSomething(new Foo());
doSomething(new Bar());
So by allowing access to static methods via the object instance, you can more easily call a static function of the same name across different types.
Now I don't know if there is a good reason why accessing the static method via -> is allowed. PHP (5.3?) also supports:
$obj::staticMethod();
which is perhaps less confusing. When using ::, it must be a static function to avoid warnings (unlike ->, which permits either).
In PHP, while you're allowed to access the static method by referencing an instance of the class, you don't necessarily need to do so.
For example, here is a class with a static function:
class MyClass{
public static function MyFunction($param){
$mynumber=param*2;
return $mynumber;
}
You can access the static method just by the type name like this, but in this case you have to use the double colon (::), instead of "->".
$result= MyClass::MyFunction(2);
(Please note you can also access the static method via an instance of the class as well using "-->"). For more information: http://php.net/manual/en/language.oop5.static.php
In PHP 7 it seems to be absolutely necessary for you to be able to do $this->staticFunction(). Because, if this code is written within an abstract class and staticFunction() is also abstract in your abstract class, $this-> and self:: deliver different results!
When executing $this->staticFunction() from a (non-abstract) child of the abstract class, you end up in child::staticFunction(). All is well.
However, executing self::staticFunction() from a (non-abstract) child of the abstract class, you end up in parent::staticFunction(), which is abstract, and thusly throws an exception.
I guess this is just another example of badly designed PHP.
Or myself needing more coffee...

Weird behaviour with triggering __callStatic() from non-static method

I found this weird behaviour with PHP classes (v5.3.8).
You have:
class foo {
function __call($func, $args) {
if ($func == 'bar')
echo "non-static __call";
}
static function __callStatic($func, $args) {
if ($func == 'bar')
echo "__callStatic";
}
function callMe() {
self::bar();
}
}
Then you do:
foo::bar() // outputs '__callStatic' as expected.
$f = new foo;
$f->callMe(); // outputs 'non-static __call', as I did not expect.
You see, a non-existent static method called from a non-static function triggers __call() instead of __callStatic(). I was wondering if this is supposed to work like this or is this some kind of bug?
[EDIT]
I forgot to try static::bar(); on callMe() but no, it didn't work either.
I (think I) understand inhan's comment but still... if I'm calling the class itself, not the instance or object, immediate logic for me says it should trigger __callStatic(). Oh well.
Thank you for your answers/comments.
You might be confused by what these things mean from within the context of a class method:
class B extends A {
public function test() {
A::foo();
self::foo();
static::foo();
}
}
None of those mean "call the static method named foo." It simply means "call the method named foo" at the place in the inheritance tree as specified by what is left of the colons.
Normally, without magic, you only have one function named foo, so the meaning is straightforward. However, when you overload with both magic methods, the call is ambiguous. PHP defaults to using __call() before __callStatic().
Static methods, variables belongs to classes not to objects so i think this is supposed to work like this.

PHP empty constructor

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

Calling Static Method from Class B(which extends Class A) of Class A

There was an interesting question in a practice test that I did not understand the answer to. What is the output of the following code:
<?php
class Foo {
public $name = 'Andrew';
public function getName() {
echo $this->name;
}
}
class Bar extends Foo {
public $name = 'John';
public function getName() {
Foo::getName();
}
}
$a = new Bar;
$a->getName();
?>
Initially, I thought this was produce an error because static methods can not reference $this (atleast in PHP5). I tested this myself and it actually outputs John.
I added Foo::getName(); at the end of the script and did get the error I was expecting. So, what changes when you call a static method from within a class that extends the class you're calling from?
Would anyone mind explaining in detail exactly what is going on here?
Foo::getName() is using an older PHP4 style of scope resolution operator to allow an overridden method to be called.
In PHP5 you would use parent::getName() instead
It's useful if you want to extend, rather than completely override the behaviour of the base class, e.g. this might make it clearer
class Bar extends Foo {
public $name = 'John';
public function getName() {
echo "My name is ";
parent::getName();
}
}
If you call the static method bound to the other object, the method is executed in the context of the current object. Which allows access to the $this-object.
Better way to call the superclass-method from inside the subclass would be:
parent::getName();
$this to the object in whose context the method was called. So: $this is $a->getName() is $a. $this in $fooInstance->getName() would be $fooInstance. In the case that $this is set (in an object $a's method call) and we call a static method, $this remains assigned to $a.
Seems like quite a lot of confusion could come out of using this feature. :)
When you call $a->getName() you're referencing a specific object, $a, which is of class Bar and so returns "John".
Foo::getName() isn't valid outside the function because there's no specific object.
I'm not sure it works in PHP, but if you cast the object to the superclass as in (Foo)$a->getName() then you'd get "Andrew" as your result. You'd still be talking about the specific object ($a) but in this case of type Foo. (Note you wouldn't generally want to do this)
Sometimes programmers are better at explaining things in code than in English!
The first thing going on here is the concept of overloading. When you instantiate Bar, it's getName() method overloads the method of the same name in Foo.
Overloading is a powerful and important part of OOD.
However, it is often useful to be able to call the version of a method that exists in the Parent class (Foo).
Here's an example:
class Dog
{
public function getTag()
{
return "I'm a dog.";
}
}
class Skip extends dog
{
public function getTag()
{
return Dog::getTag() . " My name is Skip.";
// I'm using Dog:: because it matches your example. However, you should use parent:: instead.
}
}
$o = new Skip();
echo $o->getTag(); // Echo's: "I'm a dog. My name is Skip."
Clearly this is a very parochial example but it illustrates a point.
Your base class is the most general implementation of a Type. In this case, it's "Dog." You want to put information in this base class that is common to all instances of that Type. This prevents duplication in each of the Derived classes (like "Skip").
Your script is taking advantage of this feature, perhaps inadvertently.

Categories