PHP 5.4: Getting Fully-qualified class name of an instance variable - php

I know there is a static class field on PHP 5.5, but I have to stick to PHP 5.4. Is it possible to get the fully qualified class name from a variable?
Example:
namespace My\Awesome\Namespace
class Foo {
}
And somewhere else in the code:
public function bar() {
$var = new \My\Awesome\Namespace\Foo();
// maybe there's something like this??
$fullClassName = get_qualified_classname($var);
// outputs 'My\Awesome\Namespace\Foo'
echo $fullClassName
}

You should be using get_class
If you are using namespaces this function will return the name of the class including the namespace, so watch out if your code does any checks for this.
namespace Shop;
<?php
class Foo
{
public function __construct()
{
echo "Foo";
}
}
//Different file
include('inc/Shop.class.php');
$test = new Shop\Foo();
echo get_class($test);//returns Shop\Foo
This is a direct copy paste example from here

I know this is an old question, but for people still finding this, I would suggest this approach:
namespace Foo;
class Bar
{
public static function fqcn()
{
return __CLASS__;
}
}
// Usage:
use Foo\Bar;
// ...
Bar::fqcn(); // Return a string of Foo\Bar
If using PHP 5.5, you can simply do this:
namespace Foo;
class Bar
{}
// Usage:
use Foo\Bar;
// ...
Bar::class; // Return a string of Foo\Bar
Hope this helps...
More info on ::class here.

For developers using PHP 8.0 and above, you can now easily do this without get_class.
PHP8 introduced the support for ::class on objects. Example:
public function bar() {
$var = new \My\Awesome\Namespace\Foo();
echo $var::class;
}
Here's the RFC for more info.

Related

Use unknown class in the another class

I want to use an unknown class with a variable in another class:
Example
$classandmethod = "index#show";
namespace Lib\abc;
use Lib\xyz;
class abc{
function controller($classandmethod)
{
$a = explode("#", $classandmethod);
use Lib\Controller\.$a[0];
}
}
But maybe it's not true, please help everyone!
From the manual:
The use keyword must be declared in the outermost scope of a file (the global scope) or inside namespace declarations
So you can't use a class where you're trying to do it. Then, to instantiate a class from a different namespace from a variable, rather than useing it, supply the whole namespaced class:
<?php
namespace G4\Lib
{
class A
{
public $a = "test";
}
}
namespace G4
{
class B
{
public $a;
public function __construct($class)
{
$class = "\\G4\\Lib\\".$class;
$this->a = new $class; // here's the magic
}
}
$b = new B("A");
var_dump($b->a); // test
}
Demo
The main problem is that use cannot have a variable as part of it as it's used when parsing the file and the variable is only available at runtime.
This is an example of how you can do what you seem to be after...
<?php
namespace Controller;
ini_set('display_errors', 'On');
error_reporting(E_ALL);
class Index {
public function show() {
echo "Showing...";
}
}
$classandmethod = "Controller\Index#show";
list($className,$method) = explode("#", $classandmethod);
$a= new $className();
$a->$method();
This displays...
Showing...
You could of course say that all of these classes must be in the Controller namespace and so the code will change to
$classandmethod = "Index#show";
list($className,$method) = explode("#", $classandmethod);
$className = "Controller\\".$className;
$a= new $className();
$a->$method();

PHP - Treating a class as an object

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.

Cannot access class constant from an instance using the :: scope operator

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;
}
}

accessing static methods using a variable class name (PHP)

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

instantiate a class from a variable in PHP?

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"));

Categories