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
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.
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 {
can you initialize a static array of objects in a class in PHP? Like you can do
class myclass {
public static $blah = array("test1", "test2", "test3");
}
but when I do
class myclass {
public static $blah2 = array(
&new myotherclass(),
&new myotherclass(),
&new myotherclass()
);
}
where myotherclass is defined right above myclass.
That throws an error however; is there a way to achieve it?
Nope. From http://php.net/manual/en/language.oop5.static.php:
Like any other PHP static variable, static properties may only be
initialized using a literal or constant; expressions are not allowed.
So while you may initialize a static property to an integer or array
(for instance), you may not initialize it to another variable, to a
function return value, or to an object.
I would initialize the property to null, make it private with an accessor method, and have the accessor do the "real" initialization the first time it's called. Here's an example:
class myclass {
private static $blah2 = null;
public static function blah2() {
if (self::$blah2 == null) {
self::$blah2 = array( new myotherclass(),
new myotherclass(),
new myotherclass());
}
return self::$blah2;
}
}
print_r(myclass::blah2());
While you cannot initialize it to have these values, you can call a static method to push them into its own internal collection, as I've done below. This may be as close as you'll get.
class foo {
public $bar = "fizzbuzz";
}
class myClass {
static public $array = array();
static public function init() {
while ( count( self::$array ) < 3 )
array_push( self::$array, new foo() );
}
}
myClass::init();
print_r( myClass::$array );
Demo: http://codepad.org/InTPdUCT
Which results in the following output:
Array
(
[0] => foo Object
(
[bar] => fizzbuzz
)
[1] => foo Object
(
[bar] => fizzbuzz
)
[2] => foo Object
(
[bar] => fizzbuzz
)
)
I'm programming an object instance to other objects.
Now I need to validate an object instantiated.
The code i'm using is correct, but the objects are children of another object, so further back methods of parents.
Code:
<?php
class MyParentClass
{
...
$objectName = "subClassExample";
$obj = new $objectName();
print_r( get_class_methods( $obj ) );
...
}
?>
Return :
Array ( [0] => __construct [1] => myMethod )
The SubClass:
<?php
class subClassExample extends parentClass
{
public function myMethod()
{
return null;
}
}
?>
I need to return:
Array ( [0] => myMethod )
The parent Class:
<?php
class parentClass
{
function __construct ()
{
return null;
}
}
?>
I hope I can help, I really appreciate it.
Greetings!
P.S.: Excuse my English is not my language, I speak Spanish and Norwegian Bokmal.
You can do this with PHP's ReflectionÂDocs:
class Foo
{
function foo() {}
}
class Bar extends Foo
{
function bar() {}
}
function get_class_methodsA($class)
{
$rc = new ReflectionClass($class);
$rm = $rc->getMethods(ReflectionMethod::IS_PUBLIC);
$functions = array();
foreach($rm as $f)
$f->class === $class && $functions[] = $f->name;
return $functions;
}
print_r(get_class_methodsA('Bar'));
Output:
Array
(
[0] => bar
)
You may do this check inside a child or a parent class if you need only UNIQUE child's methods:
$cm = get_class_methods($this); //Get all child methods
$pm = get_class_methods(get_parent_class($this)); //Get all parent methods
$ad = array_diff($cm, $pm); //Get the diff
Keep in mind: get_class_methods returns all types of methods (public, protected etc.)