I liked the idea presented in this answer allowing having something like multiple constructors in PHP. The code I have is similar to:
class A {
protected function __construct(){
// made protected to disallow calling with $aa = new A()
// in fact, does nothing
};
static public function create(){
$instance = new self();
//... some important code
return $instance;
}
static public function createFromYetAnotherClass(YetAnotherClass $xx){
// ...
}
class B extends A {};
$aa = A::create();
$bb = B::create();
Now I want to create a derived class B, which would use the same "pseudo-constructor", because it is the same code. However, in this case when I do not code the create() method, the self constant is the class A, so both variables $aa and $bb are of class A, while I wish $bb be class B.
If I use $this special variable, this of course would be class B, even in A scope, if I call any parent method from B.
I know I can copy the entire create() method (maybe Traits do help?), but I also have to copy all "constructors" (all create* methods) and this is stupid.
How can I help $bb to become B, even if the method is called in A context?
You want to use static, which represents the class in which the method is called. (self represents the class in which the method is defined.)
static public function create(){
$instance = new static();
//... some important code
return $instance;
}
Refer to the documentation on Late Static Bindings.
You'll need PHP 5.3+ to use this.
Related
I have 2 classes declared like in the example below.
class A{
protected $process;
public function __construct() {
......
$this->process=new B();
}
public function do_something(){
....
}
}
class B{
// content not important
// I need to call do_something from class A
}
My question is, how can I call from class B the method do_something() from class A? Is it possible?
From your example it is impossible for instance of B to know that it is instantiated and stored by an instance of class A. You need to create that connection explicitly in some way.
I didn't think this would even work, but apparently you can pass instance of A to B before A is even done with its constructor:
class A {
protected $process;
public function __construct() {
$this->process = new B( $this );
}
public function do_something() {
var_dump( 'do_something' );
}
public function test() {
$this->process->test();
}
}
class B {
public function __construct( A $a ) {
$this->a = $a;
}
public function test() {
$this->a->do_something();
}
}
$a = new A();
$a->test(); // do_something
It's hard to give an advice on what the best approach for your particular case would be, as we don't know what either A or B does.
There's a few ways to achieve this. One way would be to make B and extension of A - thereby allowing all methods of the class A to be callable on the object B. Another way is to create a new object of A inside B and call that method. Or you can pass
Here's an example where B is extended from A. By doing this, all properties and methods of A can be called on B, unless overwritten in B.
class A {
public function doSomething(){
echo "doSomething() called in A";
}
}
class B extends A {
public function someMethod() {
$this->doSomething();
}
}
$b = new B();
$b->someMethod();
The above would output doSomething() called in A.
Or, you can create an object A and call that method inside B.
class B {
public function someMethod() {
$a = new A();
$a->do_something();
}
}
$b = new B();
$b->someMethod();
After reading all the answers and doing some research i think that the best method for me was the use of Traits
"Traits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies."
So i declared a Trait with the method do_something and call that method from Both class A and Class B
Thanks
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.
I have some code:
class a {
public static function getCl() {
echo __CLASS__;
}
public function test() {
static::getCl();
}
}
class b extends a {
public static function getCl() {
echo __CLASS__;
}
}
$testClass = new b();
$testClass->test();
and this result : b. Then i try this:
class a {
public static function getCl() {
echo __CLASS__;
}
public function test() {
$this->getCl();
}
}
class b extends a {
public static function getCl() {
echo __CLASS__;
}
}
$testClass = new b();
$testClass->test();
this result is still b. I already know the different between static:: and self:: but can someone show me what is the different between static:: and $this-> in my code. Which one should i use?
Your context will produce the same result.
Here is simply description about both.
static:- refers late static binding 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.
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:
While Late static bindings tries to solve that limitation by introducing a keyword that references the class that was initially called at runtime. Basically, a keyword that would allow you to reference child class from parent class method. It was decided not to introduce a new keyword but rather use static that was already reserved.
$this:- refers current object.
Once inside an object's function, you have complete access to its variables, but to set them you need to be more specific than just using the variable name you want to work with. To properly specify you want to work with a local variable, you need to use the special $this variable, which PHP always sets to point to the object you are currently working with.
Let's suppose I have a parent class in PHP like this:
class A {
private $property;
public static function factory($arg) {
$object = new A();
$object->property = $arg;
return $object;
}
}
And I want to extend it in this way:
class B extends A {
public static function factory() {
return parent::factory('constant');
}
}
When I do B::factory() I get a object of type A. What if I want an object of type B? I cannot change anything in the code of class A.
1st version
That's because you hardcoded the A class in the factory method.
In class A, instead of $object = new A() try (require Php 5.3):
$class_name = get_called_class();
$object = new $class_name;
get_called_class() "Gets the name of the class the static method is called in."
Shorter version:
$object = new static();
2nd version (hardcoded parent class):
Copy object properties manually:
$parent = parent::factory($args);
$obj = new static();
$obj->setTimestamp($parent->getTimestamp());
$obj->setTimezone($parent->getTimezone());
return $obj;
Or use an hack to do it autoatically:
How to Cast Objects in PHP
In your example:
You have two classes (unleast)
both classes can be instantiated (concrete, not pure or abstract)
one class is a superclass of another
both classes are instantiated with a "factory" method
the "factory" method of a subclass can invoke the the "factory" method of the superclass
each "factory" method can have several type or count of parameters
Problem
Now, this is what it got my attention:
class B extends A {
public static function factory() {
return parent::factory('constant');
}
}
Short & Quick answer:
Change that to:
class B extends A {
public static function factory() {
return A::factory('constant');
}
}
Long boring hipster extended answer:
You are attempting to overriding ( and overloading, with different parameters ) a static function.
Its a common mistake, that assume that static methods are virtual, and can be overrided. Some programming languages allow that (Object Pascal, Delphi), other don't (C#, Java), PHP depends on the version, I think.
To be honest, "static functions" work similar like global functions with a namespace, that have public access to all members of a class, Instead of methods. I suggest to see them as global functions, always.
Cheers.
What's the difference between these object callings?
Non Static:
$var = new Object;
$var->function();
Static:
$var = User::function();
And also inside a class why should I use the static property for functions?
example:
static public function doSomething(){
...code...
}
Static functions, by definition, cannot and do not depend on any instance properties of the class. That is, they do not require an instance of the class to execute (and so can be executed as you've shown without first creating an instance). In some sense, this means that the function doesn't (and will never need to) depend on members or methods (public or private) of the class.
Difference is in the variable scope. Imagine you have:
class Student{
public $age;
static $generation = 2006;
public function readPublic(){
return $this->age;
}
public static function readStatic(){
return $this->age; // case 1
return $student1->age; // case 2
return self::$generation; // case 3
}
}
$student1 = new Student();
Student::readStatic();
You static function cannot know what is $this because it is static. If there could be a $this, it would have belonged to $student1 and not Student.
It also doesn't know what is $student1.
It does work for case 3 because it is a static variable that belongs to the class, unlike previous 2, which belong to objects that have to be instantiated.
Static methods and members belong to the class itself and not to the instance of a class.
Static functions or fields does not rely on initialization; hence, static.
Questions regarding STATIC functions keep coming back.
Static functions, by definition, cannot and do not depend on any instance properties of the class. That is, they do not require an instance of the class to execute (and so can be executed.
In some sense, this means that the function doesn't (and will never need to) depend on members or methods (public or private) of the class.
class Example {
// property declaration
public $value = "The text in the property";
// method declaration
public function displayValue() {
echo $this->value;
}
static function displayText() {
echo "The text from the static function";
}
}
$instance = new Example();
$instance->displayValue();
$instance->displayText();
// Example::displayValue(); // Direct call to a non static function not allowed
Example::displayText();