How to get property class namespace in php 5.6 via reflection - php

I want to get the namespace of a class property through ReflectionClass.
namespace Foo\Bar;
use Foo\Quux\B;
class A{
/**
* #var B $b
*/
protected $b = null;
...
}
In another class I'm creating a ReflectionClass object and trying to get the namespace of property b so I could create ReflectionClass for it's class.
$namespace = "Foo\\Bar";
$classname = "A";
$rc = new \ReflectionClass("$namespace\\$classname");
$type = getVarType($rc->getProperty("b")->getDocComment()); // returns B
$ns = $rc->getProperty("b")-> ... // I want to find out the namespace of class B
$rc1 = new \ReflectionClass("$ns\\$type");
Is there a possibility to find out which namespaces the class A uses?
Then I could pair the namespaces which class A is using with the discovered property type.
I know I can solve this problem with a type hinting like this: #var Foo\Quux\B $b, but I have many classes like the class A with many properties and methods using types like b and I don't want to refactor the whole code.
Is it possible to find the namespaces from the use statement or I have to use explicit type hinting?
Thanks!

You should be able to use getNamespaceName to find that out, but getProperty can tell you that as well
namespace Foo;
class A {
protected $something;
}
namespace Bar;
class B {
protected $a;
public function __construct(){
$this->a = new \Foo\A();
}
}
$reflection = new \ReflectionClass('Bar\\B');
$a = $reflection->getProperty("a");
var_dump($a);
You'll get
object(ReflectionProperty)#2 (2) {
["name"]=> string(1) "a"
["class"]=> string(5) "Bar\B"
}

One solution is to find the use statement which declare the class used in your doc comment. This will make it possible to retrieve the full namespace from the class name.
You cannot do that directly using ReflectionClass but this post can be interesting or you can use BetterReflection for that.

Related

Are protected attributes available to parent classes in PHP?

I know that protected attributes are available to subclasses when they are defined in a class, but are they available in parent classes? For example:
class My_Class {
// Is $name available here?
}
class My_Subclass extends My_Class {
protected $name = 'Henry';
}
Code which you write in the parent class can access that property if run in the context of a subclass. Made sense? Example:
class My_Class {
public function test() {
echo $this->name;
}
}
class My_Subclass extends My_Class {
protected $name = 'Henry';
}
$a = new My_Class;
$b = new My_Subclass;
$a->test(); // doesn't work
$b->test(); // works
Obviously (hopefully), instances of My_Class won't suddenly sprout a name property, so $a->test() won't work. Precisely because of that it's a very bad idea to make a class rely on properties which it doesn't define.
Visibility doesn't only relate to $this BTW, watch:
class My_Class {
public function test($obj) {
echo $obj->name;
}
}
class My_Subclass extends My_Class {
protected $name = 'Henry';
}
$a = new My_Class;
$a->test(new My_Subclass); // Amazeballs, it works!
A parent class has access to the property if and when it tries to access it. That doesn't mean all parent classes suddenly get a copy of that property themselves.
The parent class has no information about its subclasses, so no, $name is not available in My_Class.
Edit: As #deceze points out correctly in a comment code in My_Class can access $name, but that only works if the object was instantiated from a subclass implementing that variable. Accessing the variable in the parent class will give an Undefined Property notice.
Also I would consider that bad style and architecture, but that's my opinion ;)
Sometimes it 'can', but you really shouldn't do it
class A {
function set() {
$this->v = 'a';
}
function get() {
return $this->v;
}
}
class B extends A{
protected $v = 'b';
}
echo $b->get();//b
$b->set();
echo $b->get();//a
var_dump($b); //class B#1 (1) { protected $v => string(1) "a"}
$a = new A();
echo $a->get(); //Undefined property: A::$v
$a->set();
$a->get();//a
var_dump($a); //class A#2 (1) { public $v => string(1) "a"}
No. "protected" access modifier makes any property and method to be visible from the derived class. This is what it is used for. But parent class never knows any information about the derived class.
For more information please see this article.

Why can a child class not access a parent class propety without a construct method?

This might be basic knowledge, but I am curious as I do not know it yet myself. Why in PHP (and assuredly other languages) when using classes must a child class use a construct method to access the parent class' properties. In case this is unclear I will include an example.
<?php
class aClass
{
protected $aProperty = "Some value";
}
class aDifferentClass extends aClass
{
public $aDifferentProperty;
public function __construct()
{
$this->$aDifferentProperty = $this->aProperty;
}
?>//Works.
Instead of:
<?php
class aClass
{
protected $aProperty = "Some value";
}
class aDifferentClass extends aClass
{
public $aDifferentProperty = $this->$aProperty;
}
?>//Doesn't work.
Its not a matter of needing the constructor its a matter of WHEN you're trying to access it. A class is a blueprint for an object -- when you're trying to assign the property, as you've done in your example above, ie.
public $aDifferentProperty = $this->aProperty;
There is no object, and thus "this" does not yet exist. But, instead, this would work:
class A {
protected $a_property = "BOOYEA!";
}
class B extends A {
public function show_me_a_prop() {
echo $this->a_property;
}
}
$object = new B();
$object->show_me_a_prop();
So, to answer your question, you must wait until after the object has been constructed to access the properties because until its constructed, its not an object, just a blueprint for an object.
Now, to take this a bit further, you'd not allowed to assign variables directly to properties (see http://php.net/manual/en/language.oop5.properties.php ) but you can assign a constant. So here's a similar example which does work:
class A {
const a_property = "BOOYEA!";
}
class B extends A {
public $b_property = self::a_property;
}
$object = new B();
echo $object->b_property;
The "__construct" was introduced in PHP5 and it is the right way to define your constructors (in PHP4 you used the name of the class for a constructor).
You are NOT REQUIRED to define a constructor in your class, but if you wish to pass any parameters on object construction THEN YOU NEED ONE.
Also...If further down the track you change the class the child class inherits from, you don't have to change the construct call to the parent.
much easier to call parent::__construct() instead of parent::ClassName(), as it is reusable among classes and the parent can be changed easily.

PHP Store reference to abstract class in variable

1) Is it possible to store a reference to an abstract class in a variable like so:
abstract class A implements X {}
$A = A; //This doesn't work
2) Ultimately I want to be able to pass a reference to an abstract class to a method or function.
class Y { public function __construct(X $X){} }
$Y = new Y($A);
It would even be satisfactory to be able to do something like this:
abstract class A { public static $staticProperty; }
class Y {
public function __construct($X){
echo $X::$staticProperty; //Doesn't work
}
}
$Y = new Y('A');
As you cannot instantiate an abstract class, you're restricted to working with static properties (and constants) only. And since PHP 5.3, you can use variables to specify the queried class, with only restriction:
As of PHP 5.3.0, it's possible to reference the class using a
variable. The variable's value can not be a keyword (e.g. self, parent
and static).
So you can pass a classname instead; it will work as an anchor for an abstract class. For example (demo):
abstract class Foo { static $bar = 5; }
abstract class Bah { static $bar = 6; }
function echoBar($classname) {
echo $classname::$bar;
}
echoBar('Foo'); // 5
echoBar('Bah'); // 6

PHP namespaced class within variable

Can anyone explain why the below code causes a "Cannot find class" error? Instantiating the class with the fully qualified name works, but eliminates the advantage of the "use" statement.
<?php
namespace
{
use Foo\Bar;
new Bar; // Works
$class = 'Foo\Bar';
new $class; // Works
$class = 'Bar';
new $class; // "Cannot find class" error
}
namespace Foo
{
class Bar {}
}
Thanks
Well, I suppose it's actually a feature. And aliases won't help here, for the same reasons:
Importing is performed at compile-time, and so does not affect dynamic
class, function or constant names. [...]
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // instantiates object of class My\Full\Classname
$a = 'Another';
$obj = new $a; // instantiates object of class Another
?>
And yes, it sorts of defeats the purpose of use with dynamic classes.

PHP: Get class name of passed var?

I have a function that gets a class passed to it as a parameter. I would like to get the class name of the passed class as a string.
I tried putting this method in the passed class:
function getClassName()
{
return __CLASS__;
}
but if the class is extended I assumed this would return the name of the subclass but it still returns the name of the super class which I find kind of odd.
So given a $var passed to a function as a parameter, is there a way to get a string of the class name?
Thanks!!
See get_class, that should be exactly what you're trying to achieve.
$class_name = get_class($object);
Simplest way how to get Class name without namespace is:
$class = explode('\\', get_called_class());
echo end($class);
Or with preg_replace
echo preg_replace('/.*([\w]+)$/U', '$1', get_called_class());
__ CLASS __ with return the name of the class the method is implemented in.
If you want to get the class name of an object passed then you can use:
get_class($param);
Also, if you're using PHP5 then the Reflection classes provided are also useful.
Use get_class:
$className = get_class($object);
Straight from the php docs: http://uk.php.net/manual/en/function.get-class.php
<?php
abstract class bar {
public function __construct()
{
var_dump(get_class($this));
var_dump(get_class());
}
}
class foo extends bar {
}
new foo;
?>
The above example will output:
string(3) "foo"
string(3) "bar"
you could also add a method into the passed class(es) returning this:
var_dump(get_called_class());

Categories