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!
Related
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.
Here I have a bunch of entity classes composed like this:
<?php
class BaseModel {
protected $Id;
protected $CreateDate;
protected $LastUpdateDate;
// public setters, getters and validation methods
public function getClassFields(){
// how to get an array containing all property names,
// including those from inherited classes?
$array = (array) $this; //this do not work =(
return $array;
}
}
class FooModel extends BaseModel {
protected $Bar;
protected $Baz;
protected $Loo;
// public setters, getters and validation methods
}
?>
I want to get an array containing ["Id", "CreateDate", "LastUpdateDate", "Bar", "Baz", "Loo"]. How do I accomplish this?
What I've tried:
When I try to do an array cast $array = (array) new FooModel() from outside of the class or $array = (array) $this from inside of base class, both do not work... I think that get_object_vars function don't work since all properties are protected.
Should I use reflection instead?
Thank you in advance!
Here is one way to do it.
$ref = new ReflectionClass('FooModel');
$properties = $ref->getProperties();
$result = array();
foreach($properties as $i=>$prop){
$result[] = $prop->getName();
}
The $result array will hold the properties you want.
Since you are trying to get the variables from within the class, you could use a built-in function: get_class_vars.
So here is something more elaborate...
Replace your code with this:
class BaseModel {
protected $Id;
protected $CreateDate;
protected $LastUpdateDate;
// public setters, getters and validation methods
public function getClassFields(){
return array_keys(get_class_vars(get_class($this))); // changed
}
}
class FooModel extends BaseModel {
protected $Bar;
protected $Baz;
protected $Loo;
// public setters, getters and validation methods
}
And then, if you use:
$foo = new BaseModel();
print_r($foo->getClassFields());
The output is:
Array ( [0] => Id [1] => CreateDate [2] => LastUpdateDate )
If you use it on the child:
$bar = new FooModel();
print_r($bar->getClassFields());
The output is now:
Array ( [0] => Bar [1] => Baz [2] => Loo [3] => Id [4] => CreateDate [5] => LastUpdateDate )
References:
get_class: Returns the name of the class of an object
get_class_vars: Get the default properties of the class
array_keys: Return all the keys or a subset of the keys of an array
Sidenote: if you don't want your BaseModel class to be instantiated, change it to abstract:
abstract class BaseModel {
I am working on a PHP project in which a lot of classes are high leveled in the class tree, i.e. they have a lot of parent classes.
At some level, consider there is a class Food, which has quite a lot of subclasses and sub-subclasses etc. I want to implement a method getFoodClasses() in class Food that gives me an array of all subclasses that lead to the current instance, i.e. classes in the tree between class Food and the current instance, including the latter. The Food class itself and all its superclasses should not be included in the result.
Example: if a subclass of Food would be Vegetable, which has a subclass Fruit, which then has a subclass Banana, then the result of on (Banana) $b->getFoodClasses(), needs to result in `array('Vegetable', 'Fruit', 'Banana').
So,
class Food extends SomeBaseClass
{
public function getFoodClasses()
{
/* Here goes the magic! */
}
}
class Vegetable extends Food {}
class Fruit extends Vegetable {}
class Banana extends Fruit {}
$b = new Banana;
print_r($b->getFoodClasses());
Which results in:
Array
(
[0] => Vegetable
[1] => Fruit
[2] => Banana
)
I ended up with this function.
/**
* Calculates the widget path between this class and the current instance.
* #return array An array with all subclasses in the path between this class and the current instance.
*/
public function getFoodClasses()
{
$reflClass = new ReflectionClass(get_class($this));
$classes = array();
while ($reflClass->getName() != __CLASS__)
{
$classes[] = $reflClass->getName();
$reflClass = $reflClass->getParentClass();
}
return $classes;
}
Without using reflection, you can still use some simple php functions to achieve this.
class Food
{
public function getFoodClasses()
{
$class = get_class($this);
$classes = array($class);
while (($parentClass = get_parent_class($class)) && $parentClass != "Food")
{
array_unshift($classes, $parentClass); // Push onto the beginning because your example shows parents before children.
$class = $parentClass;
}
return $classes;
}
}
Just for future reference; this code actually works (starting from Banana, going to Food).
<?php
class Food
{
public function getFoodClasses()
{
}
}
class Vegetable extends Food {}
class Fruit extends Vegetable {}
class Banana extends Fruit {}
$banana = new Banana;
$class = new ReflectionClass( get_class( $banana ) );
$parents = array( );
while( $parent = $class->getParentClass( ) ) {
$parents[] = $parent->getName( );
$class = $parent;
}
var_dump( $parents );
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
)
)
Given the following case:
<?php
class ParentClass {
public $attrA;
public $attrB;
public $attrC;
public function methodA() {}
public function methodB() {}
public function methodC() {}
}
class ChildClass extends ParentClass {
public $attrB;
public function methodA() {}
}
How can I get a list of methods (and preferably class vars) that are overridden in ChildClass?
Thanks,
Joe
EDIT: Fixed bad extends. Any methods, not just public ones.
Reflection is correct, but you would have to do it like this:
$child = new ReflectionClass('ChildClass');
// find all public and protected methods in ParentClass
$parentMethods = $child->getParentClass()->getMethods(
ReflectionMethod::IS_PUBLIC ^ ReflectionMethod::IS_PROTECTED
);
// find all parent methods that were redeclared in ChildClass
foreach($parentMethods as $parentMethod) {
$declaringClass = $child->getMethod($parentMethod->getName())
->getDeclaringClass()
->getName();
if($declaringClass === $child->getName()) {
echo $parentMethod->getName(); // print the method name
}
}
Same for Properties, just you would use getProperties() instead.
You can use ReflectionClass to achieve this:
$ref = new ReflectionClass('ChildClass');
print_r($ref->getMethods());
print_r($ref->getProperties());
This will output:
Array
(
[0] => ReflectionMethod Object
(
[name] => methodA
[class] => ChildClass
)
)
Array
(
[0] => ReflectionProperty Object
(
[name] => attrB
[class] => ChildClass
)
)
See the manual for more useful information on reflection: http://uk3.php.net/manual/en/class.reflectionclass.php