How to get all the methods of a subclass? - php

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.)

Related

Access parent and child variables in method defined in parent - PHP

I have a child object that inherits from a parent. Both have a static variable which has a different value in each object; I want to add that variable from both parent and child to an array when I instantiate the child. To save duplicating code, I've written a method (addFoo) in the parent which is called from both the parent and the child constructors. However, I can't seem to find a way to distinguish between the calls when the parent constructor is called from the child constructor (as you can see below, the output from the method is the same in both cases whether using $this, self or static).
class A {
public static $foo = 'foo';
public $thisvars = array();
public $selfvars = array();
public $staticvars = array();
public function __construct() {
$this->addFoo();
}
public function addFoo() {
$this->selfvars[] = self::$foo;
$this->staticvars[] = static::$foo;
$this->thisvars[] = $this::$foo;
}
}
class B extends A {
public static $foo = 'bar';
public function __construct() {
parent::__construct();
$this->addFoo();
}
}
$b = new B;
print_r($b->selfvars);
print_r($b->staticvars);
print_r($b->thisvars);
Output:
Array
(
[0] => foo
[1] => foo
)
Array
(
[0] => bar
[1] => bar
)
Array
(
[0] => bar
[1] => bar
)
I can workaround this by passing the calling class through to the addFoo function (see below), but is there a better (correct?) way?
class C {
public static $foo = 'foo';
public $vars = array();
public function __construct() {
$this->addFoo(__CLASS__);
}
public function addFoo($class) {
$this->vars[] = $class::$foo;
}
}
class D extends C {
public static $foo = 'bar';
public function __construct() {
parent::__construct();
$this->addFoo(__CLASS__);
}
}
$d = new D;
print_r($d->vars);
Output:
Array
(
[0] => foo
[1] => bar
)
Demo on 3v4l.org
Instead of having addFoo be called by every sub-constructor, one way would be to have a single addFoos method in the base class that is called by the base constructor, that would append all the $foo values starting from the late static binding class:
class A
{
public static $foo = 'foo';
public $vars = [];
public function __construct()
{
$this->addFoos();
}
private function addFoos()
{
$class = static::class;
do {
$this->vars[] = $class::$foo;
} while ($class = get_parent_class($class));
}
}
class B extends A
{
public static $foo = 'bar';
}
class C extends B
{
public static $foo = 'baz';
}
$a = new A;
print_r($a->vars); // ['foo']
$b = new B;
print_r($b->vars); // ['bar', 'foo']
$c = new C;
print_r($c->vars); // ['baz', 'bar', 'foo']
That method is marked private as it's not supposed to be extended in this scenario (nor called from the outside).
Demo
I would alternatively consider another, more straightforward approach:
class A
{
public static $foo = 'foo';
public function getVars()
{
return [self::$foo];
}
}
class B extends A
{
public static $foo = 'bar';
public function getVars()
{
return array_merge(parent::getVars(), [self::$foo]);
}
}
class C extends B
{
public static $foo = 'baz';
public function getVars()
{
return array_merge(parent::getVars(), [self::$foo]);
}
}
$a = new A;
print_r($a->getVars()); // ['foo']
$b = new B;
print_r($b->getVars()); // ['foo', 'bar']
$c = new C;
print_r($c->getVars()); // ['foo', 'bar', 'baz']
You do have to redefine getVars on each subclass in this case, but after all, it makes sense for each class to decide which variables should be exposed. Your code becomes a bit less obscure / easier to maintain in the process.
And if a class doesn't need/want to "contribute", you can simply omit both the static property and the getVars extension for that class.
Demo
Notes:
you can easily cache the variables into a $vars property inside A if needed,
order is swapped from the other answer but you can obviously swap the array_merge if needed,
in both this sample and the one from the other answer, I'm not sure if the $foo static properties need to be public, but I've left them like they were in your question.

php: property inheritance on nested class structure

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.

Php extend method while overriding it

Is it possible to extend a parent class method while overriding it ? For example:
class Foo {
public function edit() {
$item = [1,2];
return compact($item);
}
}
class Bar extends Foo {
public function edit() {
// !!! Here, is there any way I could import $item from parent class Foo?
$item2 = [3,4]; //Here, I added (extended the method with) some more variables
return compact($item, $item2); // Here I override the return of the parent method.
}
}
The issue is that I cannot edit the Foo class in any way as it is a vendor package.
I don't want to edit the vendor methods I need to extend them (add something more to their return function)
If you used array_merge() instead it will probably show the results better...
class Foo {
public function edit() {
$item = [1,2];
return $item;
}
}
class Bar extends Foo {
public function edit() {
$item = parent::edit(); // Call parent method and store returned value
$item2 = [3,4]; //Here, I added (extended the method with) some more variables
return array_merge($item, $item2); // Here I override the return of the parent method.
}
}
$a = new Bar();
print_r($a->edit());
This will output -
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
So the call to parent::edit() will return the array from the parent class and this will be added to the array from the second class function.
Update:
I can't test this, but hopefully this will give you what your after...
class Foo {
protected function getData() {
return [1,2];
}
public function edit() {
return return view('view-file', compact($this->getData()));
}
}
class Bar extends Foo {
protected function getData() {
$item = parent::edit();
$item2 = [3,4];
return array_merge($item, $item2);
}
}
This means that the only time you create the view is in the base class, all you do is add the extra information in the derived class.

Trait that counts instances of class

I have a trait that I would like to make so I can easily count and retrieve all the instances of the class.
I know I need to push it to an array, but I don't know how I should "store" the array. Do I use public, private, static, etc?
trait Countable
{
public $all = array();
public function addToObjects()
{
//do stuff
$this->all[] = $this->somekindofproperty;
}
}
I want to be able to something like the following.
$c = new MyClass;
$objects = $c->all();
Pretty much each class with this trait should have it's own array.
Here i defined a trait with name counter and used it in a class for storing objects.
trait Counter
{
public static $all = array();
public static function addToObjects($object)
{
if (is_object($object))
{
self::$all[] = $object;
}
}
}
class CountingClass
{
use Counter;
}
class MyClass
{
public function __construct()
{
CountingClass::addToObjects($this);
}
}
$c = new MyClass;
$c = new MyClass;
$c = new MyClass;
$c = new MyClass;
print_r(CountingClass::$all);
OUTPUT:
Array
(
[0] => MyClass Object
(
)
[1] => MyClass Object
(
)
[2] => MyClass Object
(
)
[3] => MyClass Object
(
)
)

php magic method __set

I'm trying to set an ambiguous variable on a class. Something along these lines:
<?php
class MyClass {
public $values;
function __get($key){
return $this->values[$key];
}
function __set($key, $value){
$this->values[$key]=$value;
}
}
$user= new MyClass();
$myvar = "Foo";
$user[$myvar] = "Bar";
?>
Is there a way of doing this?
As has been stated $instance->$property (or $instance->{$property} to make it jump out)
If you really want to access it as an array index, implement the ArrayAccess interface and use offsetGet(), offsetSet(), etc.
class MyClass implements ArrayAccess{
private $_data = array();
public function offsetGet($key){
return $this->_data[$key];
}
public function offsetSet($key, $value){
$this->_data[$key] = $value;
}
// other required methods
}
$obj = new MyClass;
$obj['foo'] = 'bar';
echo $obj['foo']; // bar
Caveat: You cannot declare offsetGet to return by reference. __get(), however, can be which permits nested array element access of the $_data property, for both reading and writing.
class MyClass{
private $_data = array();
public function &__get($key){
return $this->_data[$key];
}
}
$obj = new MyClass;
$obj->foo['bar']['baz'] = 'hello world';
echo $obj->foo['bar']['baz']; // hello world
print_r($obj);
/* dumps
MyClass Object
(
[_data:MyClass:private] => Array
(
[foo] => Array
(
[bar] => Array
(
[baz] => hello world
)
)
)
)
Like so: http://ideone.com/gYftr
You'd use:
$instance->$dynamicName
You access member variables with the -> operator.
$user->$myvar = "Bar";

Categories