I have a class that implements an interface, and that interface extends another interface. The setting is like that:
interface A{
}
interface B extends A {
}
class C implements B {
}
$obj = new C();
I want to know which interfaces the object $obj implements. I tried to create a ReflectionClass object and then calling the getInterfaces method, but it only returns me the interface B:
$reflection = new ReflectionClass($obj);
print_r($reflection->getInterfaces());
I also tried to create a ReflectionClass object using the interface name, but when I call the getInterfaces() method, it returns an empty array.
Does any of you guys know how to get an interface name that extends a given interface?
Thanks a lot for your help,
Steve
You do not need Reflection for this. You can simply use
class_implements — Return the interfaces which are implemented by the given class
Example for your code snippet:
var_dump(class_implements($obj));
Output:
array(2) {
["B"]=>
string(1) "B"
["A"]=>
string(1) "A"
}
<?php
interface A {}
interface B extends A {}
class C implements B {}
$obj = new C();
$reflection = new ReflectionClass($obj);
echo "<pre>";
print_r($reflection->getInterfaces());
echo "</pre>";
Your example outputs this for me (IDE debugger is running on PHP 5.2.17):
Array
(
[B] => ReflectionClass Object
(
[name] => B
)
[A] => ReflectionClass Object
(
[name] => A
)
)
Related
I want to have an array with objects. For example.
public $aCarObjects = array();
$aCars = array('Audi','BMW','Ford');
foreach($aCars as $car){
array_push($aCarObjects, new Car($car));
}
// Simplified class
class Car implements C{
private $carName;
public function __construct($carName){
$this->carName = $carName;
}
}
interface C {}
This is a very shortened version of what I am trying. The class Car contains some info about the car.
When I am using the Interface C in the Car class. I cannot add objects to the array. Why is that so?
This error has nothing to do with arrays, it's a class hoisting bug (feature?) which is fixed by moving your class definition above the call to new Car. Apparently, PHP does not hoist class definitions if they implement an interface.
Here's a minimal example of the phenomenon.
Works:
new Foo();
class Foo {}
interface Bar {}
Doesn't:
new Foo(); # <-- error: Class 'Foo' not found
class Foo implements Bar {}
interface Bar {}
Perhaps this is a candidate for PHP Sadness?
Here's a working version of your code that also addresses a stray public keyword in line 1:
interface C {}
class Car implements C {
private $carName;
public function __construct($carName) {
$this->carName = $carName;
}
}
$aCarObjects = [];
$aCars = ['Audi', 'BMW', 'Ford'];
foreach ($aCars as $car) {
array_push($aCarObjects, new Car($car));
}
print_r($aCarObjects);
Output:
Array
(
[0] => Car Object
(
[carName:Car:private] => Audi
)
[1] => Car Object
(
[carName:Car:private] => BMW
)
[2] => Car Object
(
[carName:Car:private] => Ford
)
)
Try it!
It's not clear to me how class inheritance is implemented in php 5.4.7 (almost old! I know!).
Consider this example:
Class ClassA {
public $property = array();
function __construct() {
$this->property[] = "ClassA.construct";
}
public function SetA() {
$this->property[] = "ClassA.Set";
}
}
Class ClassB extends ClassA {
function __construct() {
$this->property[] = "ClassB.construct";
}
function SetB() {
$this->property[] = "ClassB.Set";
}
}
If I call in sequence
$classA = new ClassA();
$classA->SetA();
$classB = new ClassB();
$classB->SetB();
print_r($classB->property);
My expected behavior is to have...
Array
(
[0] => ClassA.construct
[1] => ClassA.Set
[2] => ClassB.construct
[3] => ClassB.Set
)
...but I obtain instead...
Array
(
[0] => ClassB.construct
[1] => ClassB.Set
)
So, what's wrong on my side?
How can I add element from a Child to an array defined on Parent object?
You misunderstand how inheritance works in general: $classA is an instance of ClassA and has nothing to do with the instance $classB of ClassB you have generated.
An instance of ClassB inherits all public and protected properties and methods of ClassA but as long as you don't use them, you will not see them.
And all instances, whether from ClassA or from ClassB, are unrelated to each other, they only have the same "template" but each has its own property values.
In PHP, parent constructors aren't called automatically, to get your behaviour you need to do the following:
Class ClassB extends ClassA {
function __construct() {
parent::__construct();
$this->property[] = "ClassB.construct";
}
function SetB() {
$this->property[] = "ClassB.Set";
}
}
And, at most, you'll get this
Array
(
[0] => ClassA.construct
[2] => ClassB.construct
[3] => ClassB.Set
)
as SetA() is never invoked
When you invoked the sequence you described, $classA and $classB are two different instances, so you will never get what you expect.
To get what you want, you need to do this:
$classB = new ClassB();
$classB->SetB();
$classB->SetA();
print_r($classB->property);
That's really simple: why did you expect the parent constructor to run if you forgot to call it in ClassB? According to https://3v4l.org/keJ2a, this has not changed since PHP 5.0.0 and still works the same in recent PHP 7 versions
If you want to get the expected result then you need to change the code as per the PHP oops concept this will not work as you want.
You Updated Code
Class ClassA {
public $property = array();
function __construct() {
$this->property[] = "ClassA.construct";
$this->SetA();
}
public function SetA() {
$this->property[] = "ClassA.Set";
}
}
Class ClassB extends ClassA {
function __construct() {
parent::__construct();//invoke parent constructor
$this->property[] = "ClassB.construct";
}
function SetB() {
$this->property[] = "ClassB.Set";
}
}
$classB = new ClassB();
$classB->SetB();
print_r($classB->property);
Expected result:
Array
(
[0] => ClassA.construct
[1] => ClassA.Set
[2] => ClassB.construct
[3] => ClassB.Set
)
When parent::__construct(); invokes then it maintains $property array variable for child class also.
Note: As we know OOPS concept, every object has a different instance.
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.
I want to get the name of my child class in the base class so that whenever an object of child class is created I get the name of the child class in my base class. Something like this:
class Base_class {
function __construct() {
// Some code Here to get the name of the child class
}
}
class Child_class extends Base_Class {}
class Another_child_class extends Base_Class {}
$object = new Child_Class;
$object2 = new Another_child_class;
When the $object is created I want the constructor to give me the name of the class from which the object was created.
Yes, to an extent. In PHP 5.5, the ::class class constant was added, which returns the class name of class to which it is applied. You can then use this in conjunction with parent, self, or static. Consider this code:
<?php
class A {}
class B extends A
{
public function foo() {
echo parent::class . "\n"; // A
echo __CLASS__ . "\n"; // B
echo self::class . "\n"; // B
echo static::class . "\n"; // D
echo get_class($this) . "\n"; // D
}
}
class C extends B {}
class D extends C {}
(new D)->foo();
self::class will return the same thing as __CLASS__, the class belonging to the function currently executing (in this case, B).
parent::class will return the name of the method's parent class (A).
static::class, by way of Late Static Binding, will return the class name of the method that was actually invoked (D).
Note, however, that you can not get the immediate child descendent of your current function (C) without using more advanced means (parsing the call stack via debug_backtrace, or via reflection).
This is certainly possible using static::class (or get_class($this) or get_called_class()) in the base class to get the name of the child (which is initially called at runtime):
<?php
class Foo
{
public function __construct()
{
var_dump(static::class, get_class($this), get_called_class());
}
}
class Bar extends Foo { }
class Baz extends Bar { }
new Foo();
new Bar();
new Baz();
Produces:
string(3) "Foo"
string(3) "Foo"
string(3) "Foo"
string(3) "Bar"
string(3) "Bar"
string(3) "Bar"
string(3) "Baz"
string(3) "Baz"
string(3) "Baz"
This is called late static binding. Here's a demo of the above.
You can use get_class() passing it the current object reference, like so:
class Base_class {
function __construct() {
$calledClassName = get_class($this);
}
}
Edit: You can find more info on get_class() in the PHP manual http://php.net/manual/en/function.get-class.php
Well, just pass it explicitly then:
class BaseClass{
function __construct($tableName){
// do stuff w/ $tableName
}
}
class ChildClass extends BaseClass{
function __construct(){
parent::__construct('ChildClass');
}
}
When concreate classes implement interface, do they return object of type interface that they are implementing? In typical factory pattern scenario the concrete classes return object of type interface they are implementing (for java and C# this is true). Does this happen in case of PHP also?
Consider the following situation..
interface IUser
{
function getName();
}
class User implements IUser
{
public function __construct( $id ) { }
public function getName()
{
return "Jack";
}
}
class UserFactory
{
public static function Create( $id )
{
return new User( $id );
}
}
$uo = UserFactory::Create( 1 );
echo( $uo->getName()."\n" );
Is object $uo an instance of type IUser or User, and why?
You never return an interface or a class, you return an object that implements the class of your choice which in turn will implement an interface.
An interface or class is the declaration and definition portion of the object that you create while the object is variable that contains the properties. Any call you do to an object resolves to a class and the body of that function is executed, but the properties you access (the non-static ones) return to the object itself.
When instanciating an object of a certain class, the object is OF that class. It cannot be of the type of an interface because an interface cannot be instanciated. On the other hand, you can use "instanceof" in PHP to determine if an object implements a certain interface or uses a specific class. Instanceof validates all interfaces implemented in all classes of the object, even the parent ones.
So using:
interface i {}
interface i2 {}
class a implements i {}
class b extends a {}
class c extends b implements i2 {}
$o = new b();
In this very case, $o is an "i", "a" and "b". All calls to instanceof with these class names will return true... But because $o is ob class b naturally, instanceof will never return true for the C class or the i2 interface.
As #raina77ow pointed out in comments, it's actually both.
You can check using instanceof
var_dump( get_class($uo) ); // User
var_dump(($uo instanceof IUser)); // true
var_dump(($uo instanceof User)); // true
From instanceof:
Lastly, instanceof can also be used to determine whether a variable is an instantiated object of a class that implements an interface: