I have a string containing the name of a class. This class is abstract, but has a public static method returning an instance of a child class.
abstract class MyClass {
public static function instance() {
return self::$inst;
}
}
Now I need to call this method somehow and all I am given is the name of the class as a string. I can't say $class = new $className() because MyClass is abstract. Any ideas?
If you have the classname in a string and want to call an abstract method of that class, you could do the following:
$className = 'MyClass';
$instance = $className::instance();
I finally found a solution for this - Reflection.
$refClass = new ReflectionClass('MyClass');
if ($refClass->hasMethod('instance') {
$refMethod = new ReflectionMethod('MyClass', 'instance');
$refMethod->invoke(null);
}
I know I am late, but if somebody is still looking, do the following:
$method = "myFunction";
$class = "myClass";
$result = $class::$method();
So in the mentioned case use
$method = "instance";
$class = "myClass"
$instance = $class::$method();
But in your case the problem seems to be in your instance function. I guess you try to return an instance of your abstract class, which is not possible !
Related
class A {
public function f(){
$this->ar[0] = 'something';
}
}
For example, how can function f be called such that $this->ar will refer to an array declared outside of class A? Assume that A is not inheriting ar.
Edit:
I tried to simplify the question. The actual code I'm looking at is
the function index in opencart's ControllerStartupStartup class
The function index is using $this to access class instances that aren't defined in that class: $this->db,$this->config, and $this->tax.
They are not declared in the parent class Controller either.
The function is being called with call_user_func_array(array($controller, $this->method), $args); in the Action class.
Maybe you can make "ar" known and provide it in the class as setter, so the instance ar is known and you can address it with $this
class A {
$ar = array();
public function f(){
$this->ar[0] = 'something';
}
}
// INSTANCE with Setter
$ar[0]='whatever';
$class = new A();
$class->ar = &$ar;
$class->f();
echo $ar[0];
I have a class that using an external package to do something
class MyClass
{
public function doSomething($data){
$external = new External();
$external->doSomething($data);
}
}
This class is called from another class, for example:
class MasterClass
{
public function go(){
$data = 'whatever';
$data2 = 'whatever2';
$myClass = new MyClass();
$myClass->doSomething($data);
$myClass->doSomething($data2);
....
}
}
So in my MasterClass I am calling the doSomething function multiple times. WHich creates a new External class multiple times - which is not really necessary.
How can I get around this issue and only create the external class once?
class MyClass
{
protected $external;
public function doSomething($data){
if(!$this->external){
$this->external = new External();
}
$this->external->doSomething($data);
}
}
But read about dependency injection in php.
Move the new External() call into the constructor and store it as a property, then reference that property in the doSomething() method instead of constructing a new instance every time.
Alternatively, if you don't want to always construct a new External whenever you construct a MyClass, you could move the construction into a Lazy Load static method called something like getExternal() in External class.
The first time that method is called it would need to store a new instance of External as a property, but on subsequent calls (when the property is already set) return the same instance. This type of pattern is called Singleton Pattern in Object-Oriented Design Patterns.
You could refer to this link to know more about singleton pattern and how it is implemented.
Pass External class in constructor.
class MyClass
{
private $external;
public function __construct(External $external)
{
$this->external = $external;
}
public function doSomething($data)
{
$this->external->doSomething($data);
}
class MasterClass
{
public function go() {
$data = 'whatever';
$data2 = 'whatever2';
$external = new External();
$myClass = new MyClass($external);
$myClass->doSomething($data);
$myClass->doSomething($data2);
....
}
}
$model = new static($variable);
All these are within a method inside a class, I am trying to technically understand what this piece of code does. I ran around in the Google world. But can't find anything that leads me to an answer. Is this just another way of saying.
$model = new static $variable;
Also what about this
$model = new static;
Does this mean I'm initializing a variable and settings it's value to null but I am just persisting the variable not to lose the value after running the method?
static in this case means the current object scope. It is used in late static binding.
Normally this is going to be the same as using self. The place it differs is when you have a object heirarchy where the reference to the scope is defined on a parent but is being called on the child. self in that case would reference the parents scope whereas static would reference the child's
class A{
function selfFactory(){
return new self();
}
function staticFactory(){
return new static();
}
}
class B extends A{
}
$b = new B();
$a1 = $b->selfFactory(); // a1 is an instance of A
$a2 = $b->staticFactory(); // a2 is an instance of B
It's easiest to think about self as being the defining scope and static being the current object scope.
self is simply a "shortcut name" for the class it occurs in. static is its newer late static binding cousin, which always refers to the current class. I.e. when extending a class, static can also refer to the child class if called from the child context.
new static just means make new instance of the current class and is simply the more dynamic cousin of new self.
And yeah, static == more dynamic is weird.
You have to put it in the context of a class where static is a reference to the class it is called in. We can optionally pass $variable as a parameter to the __construct function of the instance you are creating.
Like so:
class myClass {
private $variable1;
public function __construct($variable2) {
$this->variable1 = $variable2;
}
public static function instantiator() {
$variable3 = 'some parameter';
$model = new static($variable3); // <-this where it happens.
return $model;
}
}
Here static refers to myClass and we pass the variable 'some parameter' as a parameter to the __construct function.
You can use new static() to instantiate a group of class objects from within the class, and have it work with extensions to the class as well.
class myClass {
$some_value = 'foo';
public function __construct($id) {
if($this->validId($id)) {
$this->load($id);
}
}
protected function validId($id) {
// check if id is valid.
return true; // or false, depending
}
protected function load($id) {
// do a db query and populate the object's properties
}
public static function getBy($property, $value) {
// 1st check to see if $property is a valid property
// if yes, then query the db for all objects that match
$matching_objects = array();
foreach($matching as $id) {
$matching_objects[] = new static($id); // calls the constructor from the class it is called from, which is useful for inheritance.
}
return $matching_objects;
}
}
myChildClass extends myClass {
$some_value = 'bar'; //
}
$child_collection = myChildClass::getBy('color','red'); // gets all red ones
$child_object = $child_collection[0];
print_r($child_object); // you'll see it's an object of myChildClass
The keyword new is used to make an object of already defined class
$model = new static($variable);
so here there is an object of model created which is an instance of class static
i want to call a class method by a var (like this):
$var = "read";
$params = array(...); //some parameter
if(/* MyClass has the static method $var */)
{
echo MyClass::$var($params);
}
elseif (/* MyClass hat a non-static method $var */)
{
$cl = new MyClass($params);
echo $cl->$var();
}
else throw new Exception();
i read in the php-manual how to get the function-members of a class (get_class_methods). but i get always every member without information if its static or not.
how can i determine a method´s context?
thank you for your help
Use the class ReflectionClass:
On Codepad.org: http://codepad.org/VEi5erFw
<?php
class MyClass
{
public function func1(){}
public static function func2(){}
}
$reflection = new ReflectionClass('MyClass');
var_dump( $reflection->getMethods(ReflectionMethod::IS_STATIC) );
This will output all static functions.
Or if you want to determine whether a given function is static you can use the ReflectionMethod class:
On Codepad.org: http://codepad.org/2YXE7NJb
<?php
class MyClass
{
public function func1(){}
public static function func2(){}
}
$reflection = new ReflectionClass('MyClass');
$func1 = $reflection->getMethod('func1');
$func2 = $reflection->getMethod('func2');
var_dump($func1->isStatic());
var_dump($func2->isStatic());
One way I know of is to use Reflection. In particular, one would use ReflectionClass::getMethods as such:
$class = new ReflectionClass("MyClass");
$staticmethods = $class->getMethods(ReflectionMethod::IS_STATIC);
print_r($staticmethods);
The difficulty of this is that you need to have Reflection enabled, which it is not by default.
I have an idea of using this syntax in php. It illustrates that there are different fallback ways to create an object
function __construct() {
if(some_case())
$this = method1();
else
$this = method2();
}
Is this a nightmare? Or it works?
Or it works?
It doesn't work. You can't unset or fundamentally alter the object that is being created in the constructor. You can also not set a return value. All you can do is set the object's properties.
One way to get around this is having a separate "factory" class or function, that checks the condition and returns a new instance of the correct object like so:
function factory() {
if(some_case())
return new class1();
else
return new class2();
}
See also:
Breaking the constructor
PHP constructor to return a NULL
Why not to do something more common like:
function __construct() {
if(some_case())
$this->construct1();
else
$this->construct2();
}
You can just create class methods method1 and method2 and just write
function __construct() {
if(some_case())
$this->method1();
else
$this->method2();
}
You can make factory method.
Example:
class A {}
class B {}
class C {
function static getObject() {
if(some_case())
return new A();
else
return new B();
}
}
$ob = C::getObject();
It sounds a little bit like the Singleton class pattern.
See #Ivan's reply among others for the correct syntax for what it looks like you're trying to do.
However, there are is another alternative - use a static method as an alternative constructor:
class myclass {
function __construct() { /* normal setup stuff here */}
public static function AlternativeConstructor() {
$obj = new myclass; //this will run the normal __construct() code
$obj->somevar = 54; //special case in this constructor.
return $obj;
}
}
...
//this is how you would use the alternative constructor.
$myobject = myclass::AlternativeConstructor();
(note: you definitely can't use $this in a static method)
If you want to share some functions, do some like
class base{
'your class'
}
class A extends base{
'your class'
}
class B extends base{
'your class'
}
And call like
if(some_case())
$obj = new A();
else
$obj = new B();