How can I return an instance of the class being called, when the method is in a parent class.
Eg. In the example below, how can I return an instance of B if I call B::foo();?
abstract class A
{
public static function foo()
{
$instance = new A(); // I want this to return a new instance of child class.
... Do things with instance ...
return $instance;
}
}
class B extends A
{
}
class C extends A
{
}
B::foo(); // Return an instance of B, not of the parent class.
C::foo(); // Return an instance of C, not of the parent class.
I know I can do it something like this, but is there a neater way:
abstract class A
{
abstract static function getInstance();
public static function foo()
{
$instance = $this->getInstance(); // I want this to return a new instance of child class.
... Do things with instance ...
return $instance;
}
}
class B extends A
{
public static function getInstance() {
return new B();
}
}
class C extends A
{
public static function getInstance() {
return new C();
}
}
$instance = new static;
You're looking for Late Static Binding.
http://www.php.net/manual/en/function.get-called-class.php
<?php
class foo {
static public function test() {
var_dump(get_called_class());
}
}
class bar extends foo {
}
foo::test();
bar::test();
?>
Result
string(3) "foo"
string(3) "bar"
So your function is going to be:
public static function foo()
{
$className = get_called_class();
$instance = new $className();
return $instance;
}
All you need is :
abstract class A {
public static function foo() {
$instance = new static();
return $instance ;
}
}
Or
abstract class A {
public static function foo() {
$name = get_called_class() ;
$instance = new $name;
return $instance ;
}
}
Related
I have an abstract class and a child that extends the abstract class. The child is supposed to be a sigleton. Here is simplified example of the abstract class:
abstract class AbstractClass{
protected static $instance = NULL;
abstract protected function meInit();
private function __construct(){
$this->meInit();
$this->init();
}
private function __clone(){}
static function getInstance(){
if (is_null(self::$instance)){
self::$instance=new self;
}
return self::$instance;
}
function init(){
'code here;
}
}
Here is simplified child class:
class ChildClass_A extends AbstractClass{
protected function meInit(){
'some code;
}
}
When I try to get an instance of the child $child = ChildClass_A::getInstance(); I get this error:
Fatal error: Cannot instantiate abstract class AbstractClass in
C:\wamp\www\Classes\AbstractClass.php on line 7
I suspect the culprit is in self::$instance=new self;. How should I redo it to achieve what I need?
You're almost there; you just can't use new self() like this because it's trying to do a new A(). Instead, use get_called_class() so that a new B is created instead.
// ONLY SUPPORTS ONE SUBCLASS
// KEEP READING BELOW FOR COMPLETE SOLUTION
abstract class A {
static protected $instance = null;
abstract protected function __construct();
static public function getInstance() {
if (is_null(self::$instance)) {
$class = get_called_class();
self::$instance = new $class();
}
return self::$instance;
}
}
class B extends A {
protected function __construct() {
echo "constructing B\n";
}
}
var_dump(B::getInstance()); // constructing B, object(B)#1 (0) {}
var_dump(B::getInstance()); // object(B)#1 (0) {}
OK, but what happens now when we try to make another subclass?
class C extends A {
protected function __construct() {
echo "constructing C\n";
}
}
var_dump(C::getInstance()); // object(B)#1 (0) {}
var_dump(C::getInstance()); // object(B)#1 (0) {}
Well that sucks! I wanted a C instance, not the B one! This is because the abstract class A is only saving one instance. We have to make it support one of each subclass.
Well that's easy!
// SOLUTION:
// WORKS FOR MULTIPLE SUBCLASSES
abstract class A {
static protected $instances = array();
abstract protected function __construct();
static public function getInstance() {
$class = get_called_class();
if (! array_key_exists($class, self::$instances)) {
self::$instances[$class] = new $class();
}
return self::$instances[$class];
}
}
Class B and C can stay the same ...
class B extends A {
protected function __construct() {
echo "constructing B\n";
}
}
class C extends A {
protected function __construct() {
echo "constructing C\n";
}
}
Now let's check out how they behave
var_dump(B::getInstance()); // constructing B, object(B)#1 (0) {}
var_dump(B::getInstance()); // object(B)#1 (0) {}
var_dump(C::getInstance()); // constructing C, object(C)#2 (0) {}
var_dump(C::getInstance()); // object(C)#2 (0) {}
Oh good! Just what we always wanted!
I'm still learning OOP so this might not even be possible (although I would be surprised if so), I need some help calling another classes method.
For example in ClassA I have this method:
function getName()
{
return $this->name;
}
now from ClassB (different file, but in the same directory), I want to call ClassA's getName(), how do I do that? I tried to just do an include() but that does not work.
Thanks!
//file1.php
<?php
class ClassA
{
private $name = 'John';
function getName()
{
return $this->name;
}
}
?>
//file2.php
<?php
include ("file1.php");
class ClassB
{
function __construct()
{
}
function callA()
{
$classA = new ClassA();
$name = $classA->getName();
echo $name; //Prints John
}
}
$classb = new ClassB();
$classb->callA();
?>
If they are separate classes you can do something like the following:
class A
{
private $name;
public function __construct()
{
$this->name = 'Some Name';
}
public function getName()
{
return $this->name;
}
}
class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
}
function getNameOfA()
{
return $this->a->getName();
}
}
$a = new A();
$b = new B($a);
$b->getNameOfA();
What I have done in this example is first create a new instance of the A class. And after that I have created a new instance of the B class to which I pass the instance of A into the constructor. Now B can access all the public members of the A class using $this->a.
Also note that I don't instantiate the A class inside the B class because that would mean I tighly couple the two classes. This makes it hard to:
unit test your B class
swap out the A class for another class
You would need to have an instance of ClassA within ClassB or have ClassB inherit ClassA
class ClassA {
public function getName() {
echo $this->name;
}
}
class ClassB extends ClassA {
public function getName() {
parent::getName();
}
}
Without inheritance or an instance method, you'd need ClassA to have a static method
class ClassA {
public static function getName() {
echo "Rawkode";
}
}
--- other file ---
echo ClassA::getName();
If you're just looking to call the method from an instance of the class:
class ClassA {
public function getName() {
echo "Rawkode";
}
}
--- other file ---
$a = new ClassA();
echo $a->getName();
Regardless of the solution you choose, require 'ClassA.php is needed.
File 1
class ClassA {
public $name = 'A';
public function getName(){
return $this->name;
}
}
File 2
include("file1.php");
class ClassB {
public $name = 'B';
public function getName(){
return $this->name;
}
public function callA(){
$a = new ClassA();
return $a->getName();
}
public static function callAStatic(){
$a = new ClassA();
return $a->getName();
}
}
$b = new ClassB();
echo $b->callA();
echo $b->getName();
echo ClassB::callAStatic();
From php manual:
[...] Static method calls are resolved at compile time.
When using an explicit class name the method is already identified completely and no
inheritance rules apply. If the call is done by self then self is translated to
the current class, that is the class the code belongs to.
Here also no inheritance rules apply [...]
..so im looking for a way to emulate the standard oop inheritance with static singleton.
Code explain better:
// Normal inheritance: my goal.
class Foo{
public function test(){
echo "Foo->test()\n";
}
}
class Bar extends Foo{
public function other_test()
{
echo "Bar->other_test()\n";
}
}
$obj = new Bar();
echo get_class($obj) . "\n";
$obj->test();
$obj->other_test();
/*
Output:
Bar
Foo->test()
Bar->other_test()
*/
// How i would love to do:
class Foo2{
public static function test2()
{
echo "Foo2::test2()\n";
}
// Singleton?
public static $_instance;
public static function get_instance()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
}
class Bar2 extends Foo2{
public static function other_test2()
{
echo "Bar2::other_test2()\n";
}
}
$obj2 = Bar2::get_instance();
echo get_class($obj2) . "\n";
$obj2::test2();
$obj2::other_test2();
/*
Output:
Foo2
Foo2::test2()
Fatal error: Call to undefined method Foo2::other_test2()
*/
echo "\n-------\n";
// How im doing actually:
interface Foo3{
public static function get_instance();
}
class Bar3 implements Foo3{
// Singleton?
public static $_instance;
public static function get_instance()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
public static function test3()
{
echo "Bar3::test3()\n";
}
public static function other_test3()
{
echo "Bar3::other_test3()\n";
}
}
$obj3 = Bar3::get_instance();
echo get_class($obj3) . "\n";
$obj3::test3();
$obj3::other_test3();
/*
Output:
Bar3
Foo3::test3()
Bar3::other_test3()
*/
The last 'way' force me to avoid the get_instance and static variables to be placed in the parent class, so I do not consider it as a best solution.. if for some reason my get_instance() function will change in the future, i dont want to edit all classes (inheritance! inheritance! we all want inheritance!)
So, is there a way or a best practices to solve this problem?
p.s: php5.3.2
The Singleton pattern in PHP is something like this:
class Singleton {
private static $instance = null;
// Constructor is private, so class cannot be instantiazed from outside
private function __construct() {
}
public static function getInstance() {
if (static::$instance === null) {
static::$instance = new Singleton();
}
return static::$instance;
}
public static function test() {
echo 'Singleton::test()';
}
public function __sleep() {
throw new Exception('Serialization is not alowed.');
}
public function __wakeup() {
throw new Exception('Serialization is not alowed.');
}
public function __clone() {
throw new Exception('Cloning is not alowed.');
}
}
For you is important that keyword static, then this:
class B extends Singleton {
public static function test2() {
echo 'B::test2()';
}
}
$b = B::getInstance();
B::test();
B::test2();
// Singleton::test()
// B::test()
Is this you looking for?
I have this code:
class A
{
public $db
}
class B
{
public $cssA
public function __construct()
{
$this->cssA = new A();
}
}
The question is, how can I call a method in class B from class A?
You can't as there is no reference to the object of class B.
class A {
public $db;
private $b;
public function __construct(B $b) {
$this->b = $b;
}
}
class B {
private $a;
public function __construct() {
$this->a = new A($this);
}
}
Methods of object of class B can be now accessed through $this->b->doSomething() within object of class A.
You would have to instantiate class b within class a and then call the method...
$this->aProp = new A();
$this->aProp->classAfunction();
$aVal = $this->aProp->publicProperty;
Basic oo programming stuff.
How do i access the properties of class A from an object instantiated inside class A.
Like this;
class A()
public var1;
public obj1;
function __construct(){
$this->var1 = 'Hello World';
$this->obj1 = new B();
}
==============
class B()
function anything(){
#i want to access var1 from the calling class here ????
# how do i access var1 in the calling class
}
There's no direct way to do this. Dependency injection is a possibility:
class B {
protected $A = null;
public function __construct($A) {
$this->A = $A;
}
public function foo() {
$this->A->var1;
}
}
class A {
public function __construct() {
$this->obj1 = new B($this);
}
}