I have two classes: Action and MyAction. The latter is declared as:
class MyAction extends Action {/* some methods here */}
All I need is method in the Action class (only in it, because there will be a lot of inherited classes, and I don’t want to implement this method in all of them), which will return classname from a static call. Here is what I’m talking about:
Class Action {
function n(){/* something */}
}
And when I call it:
MyAction::n(); // it should return "MyAction"
But each declaration in the parent class has access only to the parent class __CLASS__ variable, which has the value “Action”.
Is there any possible way to do this?
__CLASS__ always returns the name of the class in which it was used, so it's not much help with a static method. If the method wasn't static you could simply use get_class($this). e.g.
class Action {
public function n(){
echo get_class($this);
}
}
class MyAction extends Action {
}
$foo=new MyAction;
$foo->n(); //displays 'MyAction'
Late static bindings, available in PHP 5.3+
Now that PHP 5.3 is released, you can use late static bindings, which let you resolve the target class for a static method call at runtime rather than when it is defined.
While the feature does not introduce a new magic constant to tell you the classname you were called through, it does provide a new function, get_called_class() which can tell you the name of the class a static method was called in. Here's an example:
Class Action {
public static function n() {
return get_called_class();
}
}
class MyAction extends Action {
}
echo MyAction::n(); //displays MyAction
Since 5.5 you can use class keyword for the class name resolution, which would be a lot faster than making function calls. Also works with interfaces.
// C extends B extends A
static::class // MyNamespace\ClassC when run in A
self::class // MyNamespace\ClassA when run in A
parent::class // MyNamespace\ClassB when run in C
MyClass::class // MyNamespace\MyClass
It's not the ideal solution, but it works on PHP < 5.3.0.
The code was copied from septuro.com
if(!function_exists('get_called_class')) {
class class_tools {
static $i = 0;
static $fl = null;
static function get_called_class() {
$bt = debug_backtrace();
if (self::$fl == $bt[2]['file'].$bt[2]['line']) {
self::$i++;
} else {
self::$i = 0;
self::$fl = $bt[2]['file'].$bt[2]['line'];
}
$lines = file($bt[2]['file']);
preg_match_all('/([a-zA-Z0-9\_]+)::'.$bt[2]['function'].'/',
$lines[$bt[2]['line']-1],
$matches);
return $matches[1][self::$i];
}
}
function get_called_class() {
return class_tools::get_called_class();
}
}
Now (when 5.3 has arrived) it's pretty simple:
http://php.net/manual/en/function.get-called-class.php
class MainSingleton {
private static $instances = array();
private static function get_called_class() {
$t = debug_backtrace();
return $t[count($t)-1]["class"];
}
public static function getInstance() {
$class = self::get_called_class();
if(!isset(self::$instances[$class]) ) {
self::$instances[$class] = new $class;
}
return self::$instances[$class];
}
}
class Singleton extends MainSingleton {
public static function getInstance()
{
return parent::getInstance();
}
protected function __construct() {
echo "A". PHP_EOL;
}
protected function __clone() {}
public function test() {
echo " * test called * ";
}
}
Singleton::getInstance()->test();
Singleton::getInstance()->test();
(PHP 5 >= 5.3.0, PHP 7)
get_called_class — The "Late Static Binding" class name
<?php
class Model
{
public static function find()
{
return get_called_class();
}
}
class User extends Model
{
}
echo User::find();
this link might be helpfull
There is no way, in the available PHP versions, to do what you want. Paul Dixon's solution is the only one. I mean, the code example, as the late static bindings feature he's talking about is available as of PHP 5.3, which is in beta.
Related
My Class is independant from another Class.
Inside my Class, a function is doing the same but refined job as a function in another Class. Can I use parent:: function_in_another_class() and get my function join that parent funciton's job flow?
No.
In PHP you can only extend from none or one class. As you write both classes are independent to each other, there is no information where to find the one or the other class.
But what you're looking for is probably this:
class A
{
function myFunction() {}
}
class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
}
public function myFunction()
{
$this->a->myFunction();
}
}
If any class method already doing the same thing why would you bother call join it?
You can not do it. If you want the same job flow best way to do is to instantiate the other class and invoke that very same method. Thats why we use OOP.
See the example,
interface Fable()
{
public function f();
}
class OtherClass implements Fable
{
public function f()
{
// job flow
}
}
class MyClass
{
private $fable;
public function __construct(Fable $f)
{
$this->fable = $f;
}
public function method1($args){
return $this->fable->f($args);
}
}
If the current class is a child of another class, yes, you can. parent references to the parent class.
From php.net:
<?php
class A {
function example() {
echo "I am A::example() and provide basic functionality.<br />\n";
}
}
class B extends A {
function example() {
echo "I am B::example() and provide additional functionality.<br />\n";
parent::example();
}
}
$b = new B;
// This will call B::example(), which will in turn call A::example().
$b->example();
?>
The best you can do here is to extend Class B from Class A
Class B extends Class A
But, you can also:
class ClassA {
function do_something($args) {
// Do something
}
}
class ClassB {
function do_something_inclassA($args) {
classA::do_something($args);
}
}
Important: calling classa::do_something(); is a static call, in other words with error reporting E_STRICT you will get a static notice warning because function do_something() is not static function do_something()
Also, calling this function statically (i.e. classa::do_something()) means that class a's function cannot refer to $this within it
I have good oop understanding but poor understanding of its implementation in php...
I have the following code, hope it's self documented =).
I need to have BB in the output
class A{
// I can't copy function::classname() to all my descendant classes
static function classname(){
echo __CLASS__;
}
}
class B extends A{
static function test(){
self::classname();
}
function test1(){
self::classname();
}
//i have A LOT of static and non-static functions using self::classname() in their code
// I can't copy all them to base class
}
$v = new B();
B::test();
$v->test1();
I'm stuck with static:: and self:: syntax
PS: another crazy question I've come across:
Suppose I have
function doSomething(){
echo $this->id;
}
Sometimes it gets into the static contexts. Yes, I know, that's because my bad application design. But is it possible to create a second(mirror, overloading) function
static function doSomething(){
echo false;
}
It means that using
$obj->doSomething() returns id and using Class::doSomething() returns false
Question 3:
Is it possible to get property default value in static context an property value in non-static context automatically?
Have a look at late static binding.
class A {
static function classname() {
echo __CLASS__;
}
static function test1() {
static::classname();
}
}
class B extends A {
static function classname() {
echo __CLASS__;
}
}
$v = new B();
B::test1();
$v->test1();
Or as pointed out by Long Ears in the comments, assuming php 5.3.0+ you can use get_called_class()
class A {
static function classname() {
echo get_called_class();
}
// this can be defined in either class A or B without affecting the output
static function test1() {
static::classname();
}
}
class B extends A {
}
$v = new B();
B::test1();
$v->test1();
Outputs:
BB
Regarding your second "crazy" question, see the Magic Methods. Basically, you would need to implement something like:
class Foo
{
public function __call($name, $arguments)
{
// call the _$name function
}
public static function __callStatic($name, $arguments)
{
// call the _{$name}_static function
}
private function _bar()
{
}
private static function _bar_static()
{
}
}
$foo = new Foo();
$foo->bar();
Foo::bar();
it's possible to add a static method like this
class Foo {
public static function __callStatic() {
// ....
}
}
// in Other file
// Call the static method
Foo-->__callStatic()
and call it on an other file (In php ) ?
<?php
class Base {
protected static $c = 'base';
public static function getC() {
return self::$c;
}
}
class Derived extends Base {
protected static $c = 'derived';
}
echo Base::getC(); // output "base"
echo Derived::getC(); // output "base", but I need "derived" here!
?>
So what's the best workaround?
The best way to solve this is to upgrade to PHP 5.3, where late static bindings are available. If that's not an option, you'll unfortunately have to redesign your class.
Based on deceze's and Undolog's input:
Undolog is right, for PHP <= 5.2 .
But with 5.3 and late static bindings it will work , just use static instead of self inside the function - now it will work...//THX # deceze for the hint
for us copy past sample scanning stackoverflow users - this will work:
class Base {
protected static $c = 'base';
public static function getC() {
return static::$c; // !! please notice the STATIC instead of SELF !!
}
}
class Derived extends Base {
protected static $c = 'derived';
}
echo Base::getC(); // output "base"
echo Derived::getC(); // output "derived"
You have to re-implment base class method; try with:
class Derived extends Base {
protected static $c = 'derived';
public static function getC() {
return self::$c;
}
}
As you see, this solution is very useless, because force to re-write all subclassed methods.
The value of self::$c depends only on the class where the method was actually implemented, not the class from which it was called.
abstract class base {
abstract public function test();
public function run()
{
self::test();
}
}
class son extends base {
public function test()
{
echo 1;
}
}
son::run();
It reports:
Fatal error: Cannot call abstract
method base::test()
But son::test() works,why and is there a way to fix?
"self" is lexically scoped, that is, if you use "self" in a method of Base, "self" means "Base", no matter how you call this method at run time. php5.3 introduced a new kind of dynamic binding, which, ironically enough, is called "static". The following works as expected in php 5.3
abstract class base {
abstract public static function test();
static public function run()
{
static::test();
}
}
class son extends base {
static public function test()
{
echo 1;
}
}
son::run();
Of course:
Fatal error: Cannot call abstract method base::test()
It has no method body you could call. If run() is supposed to be a Template Method, you refer to the class scope with $this instead of self and then create an instance of $son to call run() on it, e.g.
abstract class BaseClass {
abstract public function test();
public function run()
{
$this->test();
}
}
class Son extends BaseClass {
public function test()
{
echo 1;
}
}
$son = new Son;
$son->run(); // 1
which is rather odd, because then you could have just as well called test() directly.
Also note that in your example
son::run();
is wrong, because the run() method is not declared static and while PHP will execute run() nonetheless, it is considered wrong usage and will raise an E_STRICT error. However, if you were to define run() static, you could no longer reference $this, because a static method is not invoked from instance scope, but class scope.
Edit I was about to add the PHP5.3 solution, but see that #erenon already did that, while I was typing, so I only add the appropriate reference in the PHP Manual on Late Static Binding.
Abstract methods do not have an implementation, and thus cannot be called. If the method is not defined as abstract, and actually has an implementation, then it can be executed by your code. For example:
public function test(){
echo "Hello from base!";
}
Factory/singleton pattern mix:
class Base
{
static private $instance;
static function getSon() {
if (null === self::$instance) {
self::$instance = new Son;();
}
return self::$instance;
}
}
class Son
{
public function test() {
echo 1;
}
}
Base::getSon()->test(); //1
I need an inherited static function "call" to call another static function "inner" that has been overridden. I could do this with late static binding, but my host does not have php5.3 yet and so I need to work around it.
class ClassA{
static function call()
{
return self::inner();
}
static function inner(){
return "Class A";
}
}
class ClassB extends ClassA{
static function inner(){
return "Class B";
}
}
echo "<p>Class A = " . ClassA::call();
echo "<p>Class B = " . ClassB::call();
I would like the output to be:
Class A = Class A
Class B = Class B
But what it is:
Class A = Class A
Class B = Class A
My gut tells me that I should be able to write something in call() to detect what object was referenced when "call()" was, well, called. So instead of self::inner() it would so something along the lines of calledclass::inner(). Detecting the proper version of inner() to call from the original method call.
If performance is not an issue, you can use debug_backtrace() to find the called class:
$bt = debug_backtrace();
return get_class($bt[1]['object']);
http://php.net/manual/en/function.debug-backtrace.php
You can use object instances rather than classes. If you want a global symbol, you can use a global variable. Since they are rather unwieldy in PHP, one trick is to wrap it in a function. Eg.:
class ClassA {
function call() {
return $this->inner();
}
function inner() {
return "Class A";
}
}
function ClassA() {
static $instance;
return $instance ? $instance : new ClassA();
}
class ClassB extends ClassA {
function inner() {
return "Class B";
}
}
function ClassB() {
static $instance;
return $instance ? $instance : new ClassB();
}
echo "<p>Class A = " . ClassA()->call();
echo "<p>Class B = " . ClassB()->call();
But a better idea might be to avoid global symbols altogether; The reason why it works well in Ruby/Rails, is that Ruby doesn't really have static state in the same way that PHP has. A class can be rebound and added to at runtime, which allows for easy extension of the framework. In PHP, classes are always final, so referring to them in application code, is a very strong degree of coupling.
Unfortunately there is no nice way to do it (otherwise PHPers wouldn't cheer so much for that feature).
You have to pass class name. PHP < 5.3 also doesn't have nice syntax for static calls with dynamic class name which makes whole thing even uglier:
static function call($class)
{
return call_user_func(array($class,"inner"));
}
…
ClassA::call("ClassA");
ClassB::call("ClassB");
If you can change the code (and not use static), then singletons make it more bearable. You can make helper function to ease the syntax:
X("ClassA")->call();
X("ClassB")->call();
The X function should look up, create and return instance of a class.
Often, late static binding is needed when a child calls back a method of the parent who, in turn, calls an abstract static method of the child. I was in such a postition, and could not use static:: as my PHP was not version 5.3 (or later). The following accomplished late static binding by way of debug_backtrace().
abstract class ParentClass
{
static function parent_method()
{
$child_class_str = self::get_child_class();
eval("\$r = ".$child_class_str."::abstract_static();");
return $r;
}// CHILD MUST OVERRIDE TO PUT ITSELF INTO TRACE
protected abstract static function abstract_static(); // THIS NEEDS LATE STATIC BINDING
private static function get_child_class()
{
$backtrace = debug_backtrace();
$num = count($backtrace);
for($i = 0; $i < $num; $i++)
{
if($backtrace[$i]["class"] !== __CLASS__)
return $backtrace[$i]["class"];
}
return null;
}
}
class ChildClass extends ParentClass
{
static function parent_method(){ return parent::parent_method(); }
protected static function abstract_static()
{
return __METHOD__."()";
}// From ParentClass
}
print "The call was: ". ChildClass::parent_method();
Here's a quick example.
<?php
class ClassA{
public function call(){
return $this->inner();
}
static function inner(){
return "Class A";
}
static function init($class){
return new $class();
}
}
class ClassB extends ClassA{
static function inner(){
return "Class B";
}
}
echo "<p>Class A = " . ClassA::init("ClassA")->call();
echo "<p>Class B = " . ClassB::init("ClassB")->call();
?>
If you don't like passing in the class name you could add a static init function to the child class and explicitly pass it there as well. This would allow you to do something like: ClassA::init()->call() and ClassB::init()->call() but would have some minor code duplication.
Since you cant use static:: , or get_called_class(), or __callStatic,
you'll have to call the inner() function with some indication with
the called class (as mentioned in the other answers). An instance
of the called class would be fine.
You can add "Pseudo Static" methods to mimick every static method
you need to overwrite. This doubles your code, but
by doing this as below, I hope the code is easier to upgrade once
php5.3 comes around: just remove all the ps methods and all the
functions referencing them (and change "self" to "static" where needed ..)
class ClassA{
static function call()
{
return self::inner();
}
static function inner(){
return "Class A";
}
public function _ps_call()
{
return $this->_ps_inner();
}
}
class ClassB extends ClassA{
public static function getInstance()
{
return new self();
}
public static function call()
{
return self::getInstance()->_ps_call();
}
static function inner()
{
return "Class B";
}
public function _ps_inner()
{
return self::inner();
}
}
echo "<p>Class A = " . ClassA::call();
echo "<p>Class B = " . ClassB::call();