When using self over static - php

As of version 5.3, PHP have implemented the Late Static Bindings, which can be used to reference the called class in a context of static inheritance.
In general, the static:: seems to be more useful than self:: in a lot of contexts, mainly if you like to able that your classes and methods be extended. Seems do not make sense you call a method from your class like self::someMethod(), because it can cause a not reliable behaviour if you extended this class and override this method.
For instance (live example):
class ParentClass {
public static function someMethod () { return 'ParentClass::someMethod()'; }
public static function getSomeMethodData() { return self::someMethod(); }
}
class ChildClass extends ParentClass {
public static function someMethod () { return 'ChildClass::someMethod()'; }
}
ChildClass::getSomeMethodData();
// Return -> "ParentClass::getSomeMethodData()"
// Not -> "ChildClass ::getSomeMethodData()"
You can change this behaviour if you replace the self:: with the static::.
Okay, after the blábláblá, my question is: there are some context where we SHOULD use the self:: instead of static:: for methods or properties?
I mean, can I replace all self:: with static:: without it change my code behaviour for all my codebase?
Edit #1: to make it more clear. Which case I MUST use self:: instead of static::? I mean, in which context is inevitable the use of self::? For instance, I can consider self::class, but it can be replaced by __CLASS__ (despite I still prefer the self::class version).

There is a difference between self and static. If you call the method with static, it will be run in the context of the class where the method actually is.

Related

Why can't PHP traits have static abstract methods?

With late static binding in PHP v5.3, one can usefully declare static methods in interfaces; with traits in PHP v5.4, methods can be either static or abstract but not both. This appears to be illogical and inconsistent.
In particular, suppose one has an interface for which a trait provides all implementation, except for a static method; unless that method is declared in the trait, static analysers balk at any references thereto from within the trait. But providing a concrete implementation within the trait no longer forces implementing/using classes to provide their own implementation—which is dangerous; abstract static would be ideal, but is not allowed.
What is the explanation for this contradiction? How would you recommend resolving this problem?
interface MyInterface
{
public static function getSetting();
public function doSomethingWithSetting();
}
trait MyTrait
{
public abstract static function getSetting(); // I want this...
public function doSomethingWithSetting() {
$setting = static::getSetting(); // ...so that I can do this
/* ... */
}
}
class MyClass implements MyInterface
{
use MyTrait;
public static function getSetting() { return /* ... */ }
}
TL;DR: As of PHP 7, you can. Before then, you could define abstract static on trait, but internals deemed it bad practice.
Strictly, abstract means sub-class must implement, and static means code for this specific class only. Taken together, abstract static means "sub-class must implement code for this specific class only". Totally orthogonal concepts.
But... PHP 5.3+ supports static inheritance thanks to LSB. So we actually open that definition up a bit: self takes the former definition of static, while static becomes "code for this specific class or any of its sub-classes". The new definition of abstract static is "sub-class must implement code for this specific class or any of its sub-classes". This can lead some folks, who think of static in the strict sense, to confusion. See for example bug #53081.
What makes trait so special to elicit this warning? Well, take a look at the engine code that implements the notice:
if (ptr->flags & ZEND_ACC_STATIC && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) {
zend_error(error_type, "Static function %s%s%s() cannot be abstract", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname);
}
That code says the only place an abstract static is allowed is within an interface. It's not unique to traits, it's unique to the definition of abstract static. Why? Well, notice there's a slight corner case in our definition:
sub-class must implement code for this specific class or any of its sub-classes
With this code:
abstract class Foo {
abstract public static function get();
}
That definition means I should be able to call Foo::get. After all Foo is a class (see that keyword "class" there) and in the strict definition, get is meant to be implemented in that class Foo. But clearly that makes no sense, because well, we're back to the orthogonality of strict static.
If you try it in PHP, you get the only rationale response possible:
Cannot call abstract method Foo::get()
So because PHP added static inheritance, it has to deal with these corner cases. Such is the nature of features. Some other languages (C#, Java, etc.) don't have this problem, because they adopt the strict definition and simply don't allow abstract static. To get rid of this corner case, and simplify the engine, we may enforce this "abstract static only in interface" rule in the future. Hence, E_STRICT.
I would use a service delegate to solve the problem:
I have common method I want to use in several classes. This common method relies on a static method that must be defined externally to the common code.
trait MyTrait
{
public function doSomethingWithSetting() {
$service = new MyService($this);
return $service->doSomethingWithSetting();
}
}
class MyService
{
public function __construct(MyInterface $object) {
$this->object = $object;
}
public function doSomethingWithSetting() {
$setting = $this->object->getSetting();
return $setting;
}
}
Feels a bit Rube Goldberg though. Probably would look at the motivation for statics and consider refactoring them out.

abstract class and the use of the static keyword

Sorry if the title looks odd, I don't know how to call it. I was inspecting a framework and I wonder how this works?
<?php
//namespace and use
abstract class Model {
//...
public function __call($method,$params){
//some stuff
return static::$$method;
}
}
It's an abstract class, so to what class will static refer to? (considering it's not extending anything) I tried to var_dump method but that method is not in that class. And why does it have a double dollar sign.
EDIT: Oh it will call the __callStatic method. I need pills.
It's called "late static binding" and unlike self, which always refers to the context ("class"), where it is defined, it refers always to the context it is called on.

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...

Is passing $this to a static method tight coupling?

Here is a simple example:
class Class_A {
protected $_property;
public function method()
{
Class_B::method($this);
}
public function getProperty()
{
return $this->_property;
}
}
class Class_B {
public static function method(Class_A $classA)
{
$classA->getProperty();
}
}
$classA = new ClassA();
$classA->method();
Is it ever okay to pass $this as a parameter to the method of another class? Or is that always going to be tight coupling? I could pose another similar example using a Factory Pattern in place of the static method call.
It depends on the exact behaviour of Class_A and Class_B, but in general it would probably be better to define an interface which is implemented by Class_A and type hint for that. The methods of Class_A that are required by Class_B (e.g. getProperty()) should appear in your interface. Then, if you want to switch Class_A with another class at a later date, all it has to do is implement the same interface.
Yet again, it depends on the behavior of the classes in question, but if there was another Class_C for example that also used Class_B 's static method you might want to consider having Class_A and Class_C extend Class_B. More information can be found on the php object inheritance page.

using $this or parent:: to call inherited methods?

Not really a problem, more like curiosity on my part but as an example, say I have a php class:
class baseTestMain
{
protected function testFunction()
{
echo 'baseTestMain says hi';
}
}
and another class that extends from that class above:
class aSubClass extends baseTestMain
{
public function doingSomething()
{
parent::testFunction();
//someextrastuffhere
}
}
Normally, when I want to call a parent method when defining a new method in the subclass I would do the above - parent::methodnamehere() however instead of parent:: you can also use $this->methodname() and the operation would be the same.
class aSubClass extends baseTestMain
{
public function doingSomething()
{
$this->testFunction();
//someextrastuffhere
}
}
So what I'm asking is, should I use parent::testFunction(); or use $this->testFunction(); ? or is there a difference to it that I've missed? If not, whats your preference or the preferred method?
Do note that I am not overriding or extending that function in the subclass, essentially the implementation is carried over from the parent.
In your case, since aSubClass::testFunction() is inherited from baseTestMain::testFunction(), use $this->testFunction(). You should only use parent::testFunction() if you're going to override that method in your subclass, within its implementation.
The difference is that parent:: calls the parent's implementation while $this-> calls the child's implementation if the child has its own implementation instead of inheriting it from the parent.
Calling the method on the parent prevents the class's children from participating in polymorphism properly since their redefinition of the method will never be called.

Categories