I have a number of PHP classes inheriting a single base class. This base class offers up a static method, let's call it methodA() that can be overridden in each class, but in practice won't be overridden very much. Each class has a static variable, let's call it name that is different, but methodA() needs to be able to act based on name differently for each class. I'm new to object oriented PHP, so I'm not exactly sure how best to do this.
In Java I would make a property on the base class and then define it in the constructor method which I would then call via super(), but I'm not sure how best to do this based on static data. Am I on the right track? What would be the best way to accomplish this?
This answer was thanks to #AlexBlex.
PHP provides a feature called Late Static Bindings that allow exactly this behavior.
As of PHP 5.3.0, PHP implements a feature called late static bindings which can be used to reference the called class in a context of static inheritance.
In the example provided in the question, the way to do this would be as such:
class Base {
public static function methodA() {
return static::$name;
}
}
class A extends Base {
public static $name = "Apple";
}
class B extends Base {
public static $name = "Box";
}
You can then call the function as such with the expected results:
echo(A::methodA()); // "Apple"
echo(B::methodA()); // "Box"
This example runs in PHP 7.
Related
I have create one abstract class and declare two public functions and one abstract function.
After that I have created body for public function in abstract class but when I extending this class to Another class what the method body does not call then I want to know what is use of public methods with body class.
<?php
//declare abstract class
abstract class Test {
// declare method 1 with body
public function method1()
{
echo "hello"; //what is use of this code here
}
public function method2()
{
$this->method3();
}
abstract public function method3();
}
//extended abstract class to another class
class AnotherTest extends Test{
public function method1(){
echo "5+9"/2;
}
public function method3(){
echo 2+9;
}
public function method2()
{
echo "just for testing";
}
}
$obj = new AnotherTest();
$obj->method1();
echo nl2br("\n");
$obj->method3(9,10);
echo nl2br("\n");
$obj->method2();
?>
Writing a method body for a method of a base class provides a "default" behavior for that method on any subclasses that don't override the method.
For any (non-final) public or protected method of a base class you can do one of the following:
Accept that default behavior without modification by not defining a method with the same name in a subclass
Override and wrap that behavior by defining a new method with the same name that calls parent::methodName() in a subclass
Override and replace that behavior by defining a new method with the same name that does NOT call parent::methodName() in a subclass
The major benefit of code written like this is that it takes advantage of Polymorphism to dispatch generic method calls to specific implementations. Defining a method body instead of leaving it abstract just provides a default behavior. As this is a very abstract object-oriented programming concept, it is hard to set up an example that is both simple and not trivial. Best to look at popular codebases such as the Laravel Framework or one of the various Symfony components for examples of this concept in action.
Generally speaking you would not normally override every abstract method. If you are then you're doing something wrong and need to refactor.
Also, having the abstract (or any extended class) gives you the ability to call parent::function() which will let the parents method run then you can do your current classes additional logic.
In the end this is the basis for Polymorphism simple explanation a child class can extend a parent but act differently by changing how methods behave.
Bluntly your "Test" are just bad examples because in those cases you're right the abstract bodies are almost pointless.
I want to define a base class with static functions and an extended class which calls the static methods of its parent. As an example a base class for arrays cArray with a static method Length($arr), so a static method call
cArray::Length($myArray);
Then I want to write an extended class xArray and use it as follows:
$objArr = new xArray($arr);
$objArr->Length();
My question is whether this is ever possible. I tried many codes but all get failed for different reasons.
You should just be able to call the method statically. It will automatically call the method in the parent class, unless you have redefined the same method in the child class.
xArray::Length($arr);
To put this into code:
class cArray {
public static function Length($myArray) { ... }
}
class xArray extends cArray {
...
public function Length() {
parent::Length($this->arr);
}
}
While PHP will let you do this, it's a terrible idea. When extending classes, you should not change the method signatures fundamentally. Here you're overriding the static method cArray::Length which takes one argument with the non-static xArray::Length which takes no argument. That's a fundamentally different function and thereby a bad class structure. PHP will point this out to you if you enable strict errors.
You need to rethink your approach. There's no reason the method needs to be static in the base class and no reason it needs to change its signature in the extended class.
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...
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.
I'm attempting to access member variables in a child class via the parent class without instantiation.
This is one of my attempts but B::getStatic() fails with Access to undeclared static property.
Is there another solution to this, possibly without static?
class A {
static public function getStatic() {
return self::$myStatic;
}
}
class B extends A {
public static $myStatic = 5;
}
class C extends A {
public static $myStatic = 6;
}
var_dump(B::$myStatic);
var_dump(B::getStatic());
var_dump(C::$myStatic);
var_dump(C::getStatic());
The concept you're running into is called "Late Static Binding." Until PHP 5.3.0, there was no support for this.
If you're running 5.3.0 or higher, update the getStatic() method:
static public function getStatic() {
return static::$myStatic;
}
The others are right, the way your code is it can't be done since the variable doesn't exist at compile time.
The way to do something like this is usually with an abstract class (available in PHP5 and up, it looks like).
Class A would be the abstract class, and would have a getStatic() function. Classes B and C would extend A and have definitions for the getStatic() function. This way, when you call getStatic() you will get the value the subclass defines since there is no definition in A.
The caveat to this approach is that you can't instantiate A since it's abstract. You would ALWAYS have to make a B or a C (or a subclass there-of).
You could also make a setter in A and have the subclasses use it to set the value (instead of an '='s). That would let you instantiate A and it could set the value if it ever needs to. You might be able to make the setter private so it can't be called directly, I don't know if subclasses can use private functions in PHP.
You have a mismatch between the declaration of the function and variable.
Either you need to move the declaration of the function to B
or
move the declaration of the variable to A.
Class B inherits the properties from class A instead of the reverse.
Why don’t you use B::$myStatic like in your example?
You have to move myStatic into A. Your method getStatic in A can't access a variable that does not exist in A.
From the PHP manual:
Static references to the current class
like self:: or __CLASS__ are resolved
using the class in which the function
belongs, as in where it was defined:
So because the method is defined in A, when you call getStatic() on B or C it is trying to return a::$myStatic, which doesn't exist. Even if it did exist you would only ever get that value back, not any overridden value in a subclass.
A solution is Late Static Bindings, but this is only available in PHP 5.3 which is not yet released.
$myStatic must be declared static in class A: See here.
class A {
public static $myStatic = 5;
}
class B extends A {
public static $myStatic = 3;
}
class C extends A {
public static $myStatic = 1;
}
Then just use B::$myStatic ...