I need to assign a class (not an object) to a variable. I know this is quite simple in other programming languages, like Java, but I can't find the way to accomplish this in PHP.
This is a snippet of what I'm trying to do:
class Y{
const MESSAGE = "HELLO";
}
class X{
public $foo = Y; // <-- I need a reference to Class Y
}
$xInstance = new X();
echo ($xInstance->foo)::MESSAGE; // Of course, this should print HELLO
In php you cannot store a reference to a class in a variable. So you store a string with class name and use constant() function
class Y{
const MESSAGE = "HELLO";
}
class X{
public $foo = 'Y';
}
$xInstance = new X();
echo constant($xInstance->foo . '::MESSAGE');
You could use reflection to find it (see Can I get CONST's defined on a PHP class?) or you could a method like:
<?php
class Y
{
const MESSAGE = "HELLO";
}
class X
{
function returnMessage()
{
return constant("Y::MESSAGE");
}
}
$x = new X();
echo $x->returnMessage() . PHP_EOL;
edit - worth also pointing out that you could use overloading to emulate this behaviour and have access to a property or static property handled by a user defined method
I found out that you can treat a reference to a Class just like you would handle any regular String. The following seems to be the simplest way.
Note: In the following snippet I've made some modifications to the one shown in the question, just to make it easier to read.
class Y{
const MESSAGE="HELLO";
public static function getMessage(){
return "WORLD";
}
}
$var = "Y";
echo $var::MESSAGE;
echo $var::getMessage();
This provides a unified mechanism to access both constants and/or static fields or methods as well.
Related
I'm trying to access a class constant in one of my classes:
const MY_CONST = "value";
If I have a variable which holds the name of this constant like this:
$myVar = "MY_CONST";
Can I access the value of MY_CONST somehow?
self::$myVar
does not work obviously because it is for static properties.
Variable variables does not work either.
There are two ways to do this: using the constant function or using reflection.
Constant Function
The constant function works with constants declared through define as well as class constants:
class A
{
const MY_CONST = 'myval';
static function test()
{
$c = 'MY_CONST';
return constant('self::'. $c);
}
}
echo A::test(); // output: myval
Reflection Class
A second, more laborious way, would be through reflection:
$ref = new ReflectionClass('A');
$constName = 'MY_CONST';
echo $ref->getConstant($constName); // output: myval
There is no syntax for that, but you can use an explicit lookup:
print constant("classname::$myConst");
I believe it also works with self::.
Can I access the value of MY_CONST somehow?
self::MY_CONST
If you want to access is dynamically, you can use the reflection API Docs:
$myvar = 'MY_CONST';
$class = new ReflectionClass(self);
$const = $class->getConstant($myVar);
The benefit with the reflection API can be that you can get all constants at once (getConstants).
If you dislike the reflection API because you don't wanna use it, an alternative is the constant function (Demo):
$myvar = 'MY_CONST';
class foo {const MY_CONST = 'bar';}
define('self', 'foo');
echo constant(self.'::'.$myvar);
Just a note for Reflection: the constructor for ReflectionClass must receive the full path of the class for its parameter.
This means that just setting the string 'A' as a constructor parameter may not work in some cases.
To avoid this problem, when using ReflectionClass you will be better if you do this:
$classA = new A();
$name_classA = get_class($classA);
$ref = new ReflectionClass(get_class($name_classA));
$constName = 'MY_CONST';
echo $ref->getConstant($constName);
Function get_class will give you the full path of a class whenever you are in the code. Missing the full path may result in a "Class not found" PHP error.
have you tried
$myVar = MY_CONST or $myVar = $MY_CONST
I hit a strange problem today and even as a PHP engineer i'm stumped at this:
It seems you can access a class constant from an object instance such as:
class a {
const abc = 1;
}
$a = new a();
var_dump($a->abc);
This will output null instead of the expected 1. I was able to do the following:
class a {
const abc = 1;
}
$a = new a();
var_dump(a::abc);
But in the context of a sub object that doesn't really know who the parent is exactly, i find it extremely annoying to do:
class a {
const abc = 1;
}
$a = new a();
$c = get_class($a);
var_dump($c::abc);
Is it me or this is completly stupid, if not, please enlighten me why its working that way.
EDIT
Another way of doing it but it's not really better:
class a {
const abc = 1;
}
class b {
public function getA(){
return new a();
}
}
$b = new b();
$c = $b->getA();
var_dump($c::abc);
This last example works more like what i am doing and experiencing...
Just use the instance variable with the scope resolution operator:
$a = new a();
var_dump($a::abc);
This prints 1.
I found a relatively nice and clean way to make my problem easier to live with. Here is the solution i've applied. It is not necessarely the best but for my uses it does exactly what i need.
By creating a magic __get method, i intercept the request for the constant name from and instance point of view and i use a quick reflection to see if that constant exists and return it's value.
This allows me to actually use all in one line a pattern that looks like this:
class a {
const abc = 1;
public function __get($key){
$r = new ReflectionObject($this);
if($r->hasConstant($key)){ return $r->getConstant($key); }
}
}
class b {
public function getA(){
return new a();
}
}
$b = new b();
var_dump($b->getA()->abc);
var_dump($b->getA()->def);
Althought i'd have liked to do:
var_dump($b->getA()::abc);
var_dump($b->getA()::def);
I guess this could be possible later in 5.4+ considering we finaly have array dereferencing, we could probably ask them to add static dereferencing soon.
The PHP documentation indicates that class constants are accessed via SRO (::) rather than ->.
<?php
class MyClass
{
const constant = 'constant value';
function showConstant() {
echo self::constant . "\n";
}
}
echo MyClass::constant . "\n";
ike I mentioned, in php constants are tied to the class definition, they are static by definition and cannot be accessed using the -> operator.
If you really want to use it with your coding paradigm, you can try the reflection class in php5.
class MyClass
{
const A = "I am A";
}
$o = new ReflectionClass( "MyClass" );
echo $o->getconstant("A"); //will print "I am A"
Also, I think the example in your EDIT might not work..I did not run it, but I am not sure if the SRO(::) can be invoked on anything that is not a class reference..
I know this is an old thread, but for people who want to know the best way to do this have a look at the PHP function constant().
With constant() you can simply do this:
$a = new a();
$value = constant(get_class($a)."::abc");
// $value === 1
this has been available since PHP 4, and still works perfectly in PHP 5.5
When trying to use const defined in a class inside a different namespace, the Scope Resolution Operator (::) can be used without problems as stated by the docs prefixing the namespace before the class in which the const was declared with this format:
(<namespace>"\")*<className>::<const>
With the next namespace, class and const definitions:
models/OperationModel.php
<?php
namespace models;
class OperationModel {
const OPERATION_INITIALIZING = 1;
}
You can use the const from another namespace\class like this:
controllers/MobileController.php
<?php
namespace controllers;
use models\OpertionModel;
class MobileController {
private function thingy() {
$operation_status = models\OperationModel::OPERATION_INITIALIZING;
}
}
Example:
class LOL{
const
FOO = 1;
}
$x = new LOL;
$arr = array('x' => $x);
echo $x::FOO; // works
echo $arr['x']::FOO; // works too
But if I make my class instance a property, I can't access the constant anymore:
class WWW{
protected $lol;
public function __construct($lol){
$this->lol= $lol;
}
public function doSMth(){
echo $this->lol::FOO; // fail. parse error.. wtf
}
}
$w = new WWW;
$w->doSMth();
:(
I know I can just do echo LOL::FOO, but what if the class name is unknown? From that position I only have access to that object/property, and I really don't want that WWW class to be "aware" of other classes and their names. It should just work with the given object
You can do this much easier by assigning the lol property to a local variable, like so:
public function doSMth(){
$lol = $this->lol;
echo $lol::FOO;
}
This is still silly, but prevents having to use reflections.
If the class name is not known, you can use ReflectionClass to get the constant. Note you must be using PHP 5 or greater.
Example:
$c = new ReflectionClass($this->lol);
echo $c->getConstant('FOO'); // 1
As of PHP 5.3.0, you can access the constant via a variable containing the class name:
$name = get_class($this->lol);
echo $name::FOO; // 1
For more info, see Scope Resolution Operator - PHP
$lol = &$this->lol;
echo $lol::FOO;
..
unset($lol);
I am trying to access a static method, but using a variable as the class name. Is this possible? I seem to be having issues with it. I want to be able to do something like this:
class foo {
public static function bar() {
echo 'test';
}
}
$variable_class_name = 'foo';
$variable_class_name::bar();
And I want to be able to do similar using static variables as well.
That syntax is only supported in PHP 5.3 and later. Previous versions don't understand that syntax, hence your parse error (T_PAAMAYIM_NEKUDOTAYIM refers to the :: operator).
In previous versions you can try call_user_func(), passing it an array containing the class name and its method name:
$variable_class_name = 'foo';
call_user_func(array($variable_class_name, 'bar'));
You can use reflection for PHP 5.1 and above:
class foo {
public static $bar = 'foobar';
}
$class = 'foo';
$reflector = new ReflectionClass($class);
echo $reflector->getStaticPropertyValue('bar');
> foobar
I know this question sounds rather vague so I will make it more clear with an example:
$var = 'bar';
$bar = new {$var}Class('var for __construct()'); //$bar = new barClass('var for __construct()');
This is what I want to do. How would you do it? I could off course use eval() like this:
$var = 'bar';
eval('$bar = new '.$var.'Class(\'var for __construct()\');');
But I'd rather stay away from eval(). Is there any way to do this without eval()?
Put the classname into a variable first:
$classname=$var.'Class';
$bar=new $classname("xyz");
This is often the sort of thing you'll see wrapped up in a Factory pattern.
See Namespaces and dynamic language features for further details.
If You Use Namespaces
In my own findings, I think it's good to mention that you (as far as I can tell) must declare the full namespace path of a class.
MyClass.php
namespace com\company\lib;
class MyClass {
}
index.php
namespace com\company\lib;
//Works fine
$i = new MyClass();
$cname = 'MyClass';
//Errors
//$i = new $cname;
//Works fine
$cname = "com\\company\\lib\\".$cname;
$i = new $cname;
How to pass dynamic constructor parameters too
If you want to pass dynamic constructor parameters to the class, you can use this code:
$reflectionClass = new ReflectionClass($className);
$module = $reflectionClass->newInstanceArgs($arrayOfConstructorParameters);
More information on dynamic classes and parameters
PHP >= 5.6
As of PHP 5.6 you can simplify this even more by using Argument Unpacking:
// The "..." is part of the language and indicates an argument array to unpack.
$module = new $className(...$arrayOfConstructorParameters);
Thanks to DisgruntledGoat for pointing that out.
class Test {
public function yo() {
return 'yoes';
}
}
$var = 'Test';
$obj = new $var();
echo $obj->yo(); //yoes
I would recommend the call_user_func() or call_user_func_arrayphp methods.
You can check them out here (call_user_func_array , call_user_func).
example
class Foo {
static public function test() {
print "Hello world!\n";
}
}
call_user_func('Foo::test');//FOO is the class, test is the method both separated by ::
//or
call_user_func(array('Foo', 'test'));//alternatively you can pass the class and method as an array
If you have arguments you are passing to the method , then use the call_user_func_array() function.
example.
class foo {
function bar($arg, $arg2) {
echo __METHOD__, " got $arg and $arg2\n";
}
}
// Call the $foo->bar() method with 2 arguments
call_user_func_array(array("foo", "bar"), array("three", "four"));
//or
//FOO is the class, bar is the method both separated by ::
call_user_func_array("foo::bar"), array("three", "four"));