class substitution in php - php

Is there any way to make it work? See example :
class car {
function __construct($type){
switch ($type) {
case 'big' : return new big_car();
case 'small' : return new small_car();
}
}
function whatisit () {
echo "this is car ;( \n";
}
}
class big_car extends car {
function __construct(){}
function whatisit () {
echo "this is big car ;) \n";
}
}
class small_car extends car {
function __construct(){}
function whatisit () {
echo "this is small car ;) \n";
}
}
so the goal is to use it this way:
$mycar = new car('big');
$mycar->whatisit(); // i want it to say that it's big
I guess very much that its bad way and it cannot work this way but maybe there is a trick?
PS:: I know I can use special static method for that but...

You need a car factory to create new cars; this is not JavaScript :)
class car_factory
{
function create_car($type = null)
{
switch ($type) {
case 'big':
return new big_car();
case 'small':
return new small_car();
case null:
return new car();
}
throw new InvalidArgumentException($type);
}
}
$factory = new car_factory;
$small_car = $factory->create_car('small');
$std_car = $factory->create_car();
Of course, you should remove the __construct function from your original code.
As mentioned in the comments you could completely generalize this by using dynamic classes, assuming class extensions have the same constructor and class naming is consistent:
class car_factory
{
function create_car($type = null)
{
if (is_null($type)) {
return new car();
}
$class = "{$type}_car";
if (class_exists($class)) {
$obj = new $class();
if ($obj instanceof car) {
return $obj;
}
}
throw new InvalidArgumentException($type);
}
}
Personally I have no preferences either way; if extensibility is a key factor, go for it, otherwise stick with a simple switch.

[...]you could completely generalize this by using dynamic classes, assuming class extensions have the same constructor and class naming is consistent
You can add even more flexibility using Reflection:
class car_factory
{
function create_car($class = null, $constructorArgs = array())
{
if (is_null($class)) {
return new car();
}
try {
$refl = new ReflectionClass($class);
if (!$refl->isSubclassOf('car') {
throw new DomainException("Type: {$class} is not a car type");
}
return $refl->newIntanceArgs($constructorArgs);
} catch(ReflectionException $e) {
throw new DomainException("Invalid car type: {$class}");
}
}
}
Now use:
$factory = new car_factory();
$car1 = $factory->create_car('big_car');
$car2 = $factory->create_car('small_car');
$car3 = $factory->create_car('fancy_car_name_with_constructor_args', array("I'm fancy!"));

Related

php dynamically append method to class

Need dynamically append method to class.
My code:
<?php
class stdClass1 {
public function __call($method, $arguments) {
return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}
}
class stdClass2 {
function stdRunMethod() {
$obj = new stdClass1();
$obj->test = function() {
echo 'a simple function';
};
$obj->test();
$obj2 = new stdClass1();
$obj2->test();
}
}
$obj = new stdClass2();
$obj->stdRunMethod();
Question: why test method run only for first instance of stdClass1 class? How to append this method for all new instances?
try this instead (demo):
<?php
class stdClass1 extends \stdClass
{
private static $addedClosures = array();
public function __set($name, $value)
{
if ($value instanceof \Closure) {
self::$addedClosures[$name] = $value;
}
else {
parent::__set($name, $value);
}
}
public function __call($method, $arguments)
{
if (isset(self::$addedClosures[$method]))
return call_user_func_array(self::$addedClosures[$method], $arguments);
return call_user_func_array($method, $arguments);
}
}
class stdClass2 extends \stdClass
{
function stdRunMethod()
{
$obj = new stdClass1();
$obj->test = function () {
print_r('a simple function');
};
$obj->test();
$obj2 = new stdClass1();
$obj2->test();
}
}
The reason it only runs once is that each copy of stdClass1 maintains their own set of variables. In the following
$obj1 = new stdClass1();
$obj1->a = '1';
$obj2 = new stdClass1();
$obj2->a = '2';
echo $obj1->a;
You'll get the value 1 as the output. Because in most cases they maintain different references. Unless you use the static keyword. Static properties are shared between all instances of the class, and should be used carefully, but that's what you're thinking of. What you're thinking of can be done like this
<?php
class stdClass1 {
private static $methods = [];
public function __call($method, $arguments) {
return call_user_func_array(Closure::bind($this->methods[$method], $this, get_called_class()), $arguments);
}
public function __set($name, $value) {
if (is_callable($value)) {
$this->methods[$name] = $value;
} else {
parent::__set($name, $value);
}
}
}
Here we're using a static, defined property to hold all of the dynamic methods, and we're using the magic __set property to set the methods in to the array.
That being said, dynamically loading methods in to an object is bad. Don't do that

PHP OOP declaring a variable to an upper class

First of all, I want to write two class.
<?php
class A
{
function load($v)
{
$this->$v = "stack";
}
}
class Base
{
var $lib = null;
function __construct()
{
$this->lib = new A();
}
}
$bs = new Base();
$bs->lib->load("libx");
// Current calling method
$bs->lib->libx;
// But I want this
$bs->libx;
?>
I write a MVC fremawork.
CodeIgniter can do this but I could not.
My english is poor. Because of this, don't talk me complicated please.
You can add a magic __get method to Base to look for the property in lib, and return it if it exists:
class A
{
function load($v)
{
$this->$v = "stack";
}
}
class Base
{
var $lib = null;
function __construct()
{
$this->lib = new A();
}
public function __get($v)
{
if (property_exists($this->lib, $v)) {
return $this->lib->$v;
}
}
}
Usage:
$bs = new Base();
$bs->lib->load("libx");
echo $bs->lib->libx, PHP_EOL;
echo $bs->libx, PHP_EOL;
Output:
stack
stack

Wrong Static Method

PHP calls private method in parent class instead of method define in current class called by call_user_func
class Car {
public function run() {
return call_user_func(array('Toyota','getName')); // should call toyota
}
private static function getName() {
return 'Car';
}
}
class Toyota extends Car {
public static function getName() {
return 'Toyota';
}
}
$car = new Car();
echo $car->run(); //Car instead of Toyota
$toyota = new Toyota();
echo $toyota->run(); //Car instead of Toyota
I have found a solution with a different approach..
<?php
class Car {
public static function run() {
return static::getName();
}
private static function getName() {
return 'Car';
}
}
class Toyota extends Car {
public static function getName() {
return 'Toyota';
}
}
echo Car::run();
echo Toyota::run();
?>
Using Late Static Binding..
You might use something like this:
<?php
class Car {
public function run() {
return static::getName();
}
private static function getName(){
return 'Car';
}
}
class Toyota extends Car {
public static function getName(){
return 'Toyota';
}
}
$car = new Car();
echo $car->run();
echo PHP_EOL;
$toyota = new Toyota();
echo $toyota->run();
?>
Output:
Car
Toyota
PHP 5.4.5
This is a bug that appears to have fluctuated in and out of existence for a long time (see #deceze's tests in comments on the question). It is possible to "fix" this issue - that is, give consistent behaviour across PHP versions - using reflection:
Works in PHP 5.3.2 and later due to a dependency on ReflectionMethod::setAccessible() to invoke private/protected methods. I will add further explanation for this code, what it can and can't do and how it works very shortly.
Unfortunately it's not possible to test this directly on 3v4l.org because the code is too large, however this is the first ever real use case for minifying PHP code - it does work on 3v4l if you do this, so feel free to play around and see if you can break it. The only issue I'm aware of is that it doesn't currently understand parent. It is also restricted by the lack of $this support in closures before 5.4, there's not really anything that can be done about this though.
<?php
function call_user_func_fixed()
{
$args = func_get_args();
$callable = array_shift($args);
return call_user_func_array_fixed($callable, $args);
}
function call_user_func_array_fixed($callable, $args)
{
$isStaticMethod = false;
$expr = '/^([a-z_\x7f-\xff][\w\x7f-\xff]*)::([a-z_\x7f-\xff][\w\x7f-\xff]*)$/i';
// Extract the callable normalized to an array if it looks like a method call
if (is_string($callable) && preg_match($expr, $callable, $matches)) {
$func = array($matches[1], $matches[2]);
} else if (is_array($callable)
&& count($callable) === 2
&& isset($callable[0], $callable[1])
&& (is_string($callable[0]) || is_object($callable[0]))
&& is_string($callable[1])) {
$func = $callable;
}
// If we're not interested in it use the regular mechanism
if (!isset($func)) {
return call_user_func_array($func, $args);
}
$backtrace = debug_backtrace(); // passing args here is fraught with complications for backwards compat :-(
if ($backtrace[1]['function'] === 'call_user_func_fixed') {
$called = 'call_user_func_fixed';
$contextKey = 2;
} else {
$called = 'call_user_func_array_fixed';
$contextKey = 1;
}
try {
// Get a reference to the target static method if possible
switch (true) {
case $func[0] === 'self':
case $func[0] === 'static':
if (!isset($backtrace[$contextKey]['object'])) {
throw new Exception('Use of self:: in an invalid context');
}
$contextClass = new ReflectionClass($backtrace[$contextKey][$func[0] === 'self' ? 'class' : 'object']);
$contextClassName = $contextClass->getName();
$method = $contextClass->getMethod($func[1]);
$ownerClassName = $method->getDeclaringClass()->getName();
if (!$method->isStatic()) {
throw new Exception('Attempting to call instance method in a static context');
}
$invokeContext = null;
if ($method->isPrivate()) {
if ($ownerClassName !== $contextClassName
|| !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call private method in an invalid context');
}
$method->setAccessible(true);
} else if ($method->isProtected()) {
if (!method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call protected method in an invalid context');
}
while ($contextClass->getName() !== $ownerClassName) {
$contextClass = $contextClass->getParentClass();
}
if ($contextClass->getName() !== $ownerClassName) {
throw new Exception('Attempting to call protected method in an invalid context');
}
$method->setAccessible(true);
}
break;
case is_object($func[0]):
$contextClass = new ReflectionClass($func[0]);
$contextClassName = $contextClass->getName();
$method = $contextClass->getMethod($func[1]);
$ownerClassName = $method->getDeclaringClass()->getName();
if ($method->isStatic()) {
$invokeContext = null;
if ($method->isPrivate()) {
if ($ownerClassName !== $contextClassName || !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call private method in an invalid context');
}
$method->setAccessible(true);
} else if ($method->isProtected()) {
if (!method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call protected method in an invalid context');
}
while ($contextClass->getName() !== $ownerClassName) {
$contextClass = $contextClass->getParentClass();
}
if ($contextClass->getName() !== $ownerClassName) {
throw new Exception('Attempting to call protected method in an invalid context');
}
$method->setAccessible(true);
}
} else {
$invokeContext = $func[0];
}
break;
default:
$contextClass = new ReflectionClass($backtrace[$contextKey]['object']);
$method = new ReflectionMethod($func[0], $func[1]);
$ownerClassName = $method->getDeclaringClass()->getName();
if (!$method->isStatic()) {
throw new Exception('Attempting to call instance method in a static context');
}
$invokeContext = null;
if ($method->isPrivate()) {
if (empty($backtrace[$contextKey]['object'])
|| $func[0] !== $contextClass->getName()
|| !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call private method in an invalid context');
}
$method->setAccessible(true);
} else if ($method->isProtected()) {
$contextClass = new ReflectionClass($backtrace[$contextKey]['object']);
if (empty($backtrace[$contextKey]['object']) || !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call protected method outside a class context');
}
while ($contextClass->getName() !== $ownerClassName) {
$contextClass = $contextClass->getParentClass();
}
if ($contextClass->getName() !== $ownerClassName) {
throw new Exception('Attempting to call protected method in an invalid context');
}
$method->setAccessible(true);
}
break;
}
// Invoke the method with the passed arguments and return the result
return $method->invokeArgs($invokeContext, $args);
} catch (Exception $e) {
trigger_error($called . '() expects parameter 1 to be a valid callback: ' . $e->getMessage(), E_USER_ERROR);
return null;
}
}
Use "protected" modifier if you want to get access from parent and descendants only. IMO, it's obvious. For example:
<?php
class Car {
public function run() {
return call_user_func(array('static','getName'));
}
protected static function getName() {
return 'Car';
}
}
class Toyota extends Car {
protected static function getName() {
return 'Toyota';
}
}
$car = new Car();
echo $car->run(); // "Car"
$toyota = new Toyota();
echo $toyota->run(); // "Toyota"
You can use get_called_class() instead of 'static'.
The problem is, I think, with the different access levels of the two getname functions. If you make the base class version of getname() public (the same as the derived class version), then in php 5.3.15 (on my Mac), you get Toyota. I think that, because of the different access levels, you end up with two different versions of the getname() function in the Toyota class, rather than the derived class version overriding the base class version. In other words, you have overloading rather than overriding. Therefore, when the run() function looks for a getname() function in the Toyota class to execute, it finds two and takes the first one, which would be the first to be declared (from the base class).
Granted this is just supposition on my part, but it sounds plausible.
use the get_called_called function todo this
public function run() {
$self = get_called_class();
return $self::getName();
}
I believe you're functions are overriding each other and by default going to the first one. Unless you change the parameters of one function, or rename the function it will always default to the parent class function.

Dependency Injection Pattern seems extreme in Control Class

My Control Class basically picks which object / class to instantiate. Because this is basically what it does it naturally has many objects / classes it calls.
If I use dependency injection I will be injecting all of these objects. This seems bad for two reasons.
I've heard that about 3 dependent objects / classes is normal to KISS ( Keep it Simple Smarty)
Only one of the objects / classes will be used. So in a sense the others are instantiated for no reason.
How do I resolve these design considerations to satisfy - decoupled code, but simple and used code?
What you do is that you actually map some parameter onto some functionality, a so called script or action.
So in the end you only need a convention how to map that parameter or name onto some function. As functions can be somewhere (in some other object, in the global space, anonymous), you don't really need to inject many objects into your control class, but functions and the mapping.
If you would than even add some more differentiation with function name and parameters (or "modules" and "actions"), well then, you could drastically reduce your code and you can actually make the request inject the dependency:
Script or Action
Mapping: Actions:
"*" "_.Exception.Invalid ajax_type"
"signin_control" "A.SignIn.invoke"
"signup_control" "A.SignUp.invoke"
"tweet_control" "A.Tweet.add"
"ControlBookmark_add" "A.Bookmark.add"
"ControlBookmark_delete" "A.Bookmark.delete"
"ControlTryIt" "B.ControlTryIt"
"ControlSignOut" "C.SignOut"
Implementation:
$action = $map[isset($map[$ajax_type]) ? $ajax_type : '*'];
Session::start();
call_user_func_array(
'call_user_func_array',
explode('.', $action) + array(NULL, NULL, NULL)
);
function _($a, $b) {
throw new $a($b);
}
function A($a, $b) {
$maker = new ObjectMaker();
$maker->$a()->$b();
}
function B($a) {
new $a();
}
function C($a) {
Session::finish();
B($a);
}
This pseudo-code shows the actual business of your control class: Call some functions based on it's input. The concrete dependencies are:
ObjectMaker
Session
$map
As session is static, you should replace it with something that actually can be injected.
As $map is an array, it can be injected, but the logic of the mapping might need to become something more internal, so if $map is an ArrayAccess, this can happen already.
The non-concrete dependencies are hidden inside the actual $ajax_type, so these dependencies are dependent on that parameter through mapping, which is already a dependency. So the last dependency is:
$ajax_type
This dependency is related to both the control class and the mapping. So the control class itself could be made a dependency to the ajax type as well. But as you use a static global function, I'll simplify this inside a class function so actually dependencies can be passed into it. I put the factory into a global function and the ajax types are loaded from an ini-file:
function ajax_control_factory($inifile)
{
$maker = new ObjectMaker();
$session = new SessionWrap();
$types = new AjaxTypesIni($inifile);
return new AjaxControl($maker, $session, $types);
}
$control = ajax_control_factory($inifile);
printf("Call an nonexistent ajax type: ");
try {
$control->invokeByType('blurb');
printf(" - I so failed!\n");
} catch (Exception $e) {
printf("Exception caught! All good!\n");
}
printf("Add me a bookmark: ");
$control->invokeByType("ControlBookmark_add");
printf("Done! Fine! Superb this works!\n");
printf("Do the two control functions: ");
$control->invokeByType("ControlTryIt");
$control->invokeByType("ControlSignOut");
printf("Done! Fine! Superb this works!\n");
Ini file:
* = _.Exception.Invalid ajax_type
signin_control = A.SignIn.invoke
signup_control = A.SignUp.invoke
tweet_control = A.Tweet.add
ControlBookmark_add = A.Bookmark.add
ControlBookmark_delete = A.Bookmark.delete
ControlTryIt = B.ControlTryIt
ControlSignOut = C.SignOut
To have this work, this needs some stubs for mocking, which is easy with your example:
class Mock
{
public $stub;
public function __call($name, $args)
{
return class_exists($this->stub) ? new $this->stub() : $this->stub;
}
}
class ObjectMaker extends Mock
{
public $stub = 'Mock';
}
class ControlTryIt {}
class SignOut {}
class SessionWrap
{
public function start()
{
// session::start();
}
public function stop()
{
// session::finish();
}
}
Those are enough to run the code above which will give:
Call an nonexistent ajax type: Exception caught! All good!
Add me a bookmark: Done! Fine! Superb this works!
Do the two control functions: Done! Fine! Superb this works!
The ajax types:
class AjaxTypes extends ArrayObject
{
private $default;
private $types;
public function __construct(array $types, $default)
{
parent::__construct($types);
$this->default = $default;
}
public function offsetGet($index)
{
return parent::offsetExists($index) ? parent::offsetGet($index) : $this->default;
}
}
class AjaxTypesIni extends AjaxTypes
{
public function __construct($inifile)
{
$map = parse_ini_file($inifile);
if (!isset($map['*'])) throw new UnexpectedValueException('No * entry found.');
$default = $map['*'];
unset($map['*']);
parent::__construct($map, $default);
}
}
And the ajax controler:
class AjaxControl
{
private $types;
private $maker;
private $session;
public function __construct(ObjectMaker $maker, SessionWrap $session, AjaxTypes $types)
{
$this->types = $types;
$this->maker = $maker;
$this->session = $session;
}
public function invokeByType($type)
{
$session = $this->session;
$maker = $this->maker;
$invoke = function($action) use ($session, $maker)
{
$_ = function($a, $b)
{
throw new $a($b);
};
$A = function($a, $b) use ($maker)
{
$maker->$a()->$b();
};
$B = function ($a)
{
new $a();
};
$C = function ($a) use ($B, $session)
{
$session->stop();
$B($a);
};
$args = explode('.', $action) + array(NULL, NULL, NULL);
$func = array_shift($args);
call_user_func_array(${$func}, $args);
};
$invoke($this->types[$type]);
$this->session->start();
}
}
This is just exemplary. There is no guarantee that this fits as a design for your needs, just for demonstrating purposes. What it shows is that your actual controller function is not normalized / modular enough. When you better analyze the dependencies that exist and you inject them instead that you hardencode them, you will automatically find the best way to design your system.
What this example shows as well is that you have a tons of hidden dependencies for the request and response. You really need to draw lines somewhere and define what you pass through and in which direction. Say goodbye to global static state. Always inject. You can even start with function that need everything as parameters if it helps.
Solved:
By placing the dependency injection in the factory pattern ( Object Maker ), I can pull out all of the dependencies into one dependency - Object Maker - note below.
PHP Control
class Control
{
public static function ajax($ajax_type)
{
Session::start();
switch($ajax_type)
{
case 'signin_control': // uses Message, Text, Database
$Object = new ObjectMaker();
$ObjectSignIn=$Object->makeSignIn();
$ObjectSignIn->invoke();
break;
case 'signup_control':// uses Message, Text, Database
$Object = new ObjectMaker();
$ObjectSignUp=$Object->makeSignUp();
$ObjectSignUp->invoke();
break;
case 'tweet_control':// uses Message, Text, Database
$Object = new ObjectMaker();
$ObjectTweet=$Object->makeTweet();
$ObjectTweet->add();
break;
case 'ControlBookmark_add': // uses Message, Text, Database
$Object = new ObjectMaker();
$ObjectBookmark = $Object->makeBookmark();
$ObjectBookmark->add();
break;
case 'ControlBookmark_delete':// uses Database
$Object = new ObjectMaker();
$ObjectBookmark=$Object->makeBookmark();
$ObjectBookmark->delete();
break;
case 'ControlTryIt': // Why Not Session
new ControlTryIt();
break;
case 'ControlSignOut':
Session::finish();
new ControlSignOut();
break;
default:
throw new Exception('Invalid ajax_type');
}
}
ObjecMaker
class ObjectMaker
{
public function makeSignUp()
{
$DatabaseObject = new Database();
$TextObject = new Text();
$MessageObject = new Message();
$SignUpObject = new ControlSignUp();
$SignUpObject->setObjects($DatabaseObject, $TextObject, $MessageObject);
return $SignUpObject;
}
public function makeSignIn()
{
$DatabaseObject = new Database();
$TextObject = new Text();
$MessageObject = new Message();
$SignInObject = new ControlSignIn();
$SignInObject->setObjects($DatabaseObject, $TextObject, $MessageObject);
return $SignInObject;
}
public function makeTweet( $DatabaseObject = NULL, $TextObject = NULL, $MessageObject = NULL )
{
if( $DatabaseObject == 'small' )
{
$DatabaseObject = new Database();
}
else if( $DatabaseObject == NULL )
{
$DatabaseObject = new Database();
$TextObject = new Text();
$MessageObject = new Message();
}
$TweetObject = new ControlTweet();
$TweetObject->setObjects($DatabaseObject, $TextObject, $MessageObject);
return $TweetObject;
}
public function makeBookmark( $DatabaseObject = NULL, $TextObject = NULL, $MessageObject = NULL )
{
if( $DatabaseObject == 'small' )
{
$DatabaseObject = new Database();
}
else if( $DatabaseObject == NULL )
{
$DatabaseObject = new Database();
$TextObject = new Text();
$MessageObject = new Message();
}
$BookmarkObject = new ControlBookmark();
$BookmarkObject->setObjects($DatabaseObject,$TextObject,$MessageObject);
return $BookmarkObject;
}
}

How to get the parent object in PHP, from OUTSIDE the object itself?

I am using Reflections to adjust various values in objects, and I have an object who's parent I need to adjust.
For example:
class Ford extends Car
{
private $model;
}
class Car
{
private $color;
}
I can easily use Reflection to change the model, but how can I separate the parent from the child, so that I can use Reflection on the parent?
Some psuedo code for what I'm hoping is possible:
$ford = new Ford();
$manipulator = new Manipulator($ford);
$manipulator->set('model','F-150');
$manipulator->setParentValue('color','red');
class Manipulator
{
public function __construct($class) {
$this->class = $class;
$this->reflection = new \ReflectionClass($class);
}
public function set($property,$value) {
$property = $this->reflection->getProperty($property);
$property->setAccessible(true);
$property->setValue($this->class,$value);
}
public function setParentValue() {
$parent = $this->reflection->getParent();
$property = $this->reflection->getProperty($property);
$property->setAccessible(true);
// HOW DO I DO THIS?
$property->setValue($this->class::parent,$value);
}
}
Gist of the question:
In this case, how can I change the $color from outside the object altogether?
Is there something like Ford::parent() or get_parent_object($ford) available?
Note
The objects used above are not the exact scenario, but just used to illustrate the concept. In the real world case, I have a parent/child relationship, and I need to be able to access/change values in each from the outside.
ANSWER
Please check my answer below...I figured it out.
After extensive review, I have found that I can't access the parent of an object AS AN OBJECT outside of the object itself.
However, using Reflections, I was able to solve the example posted above:
<?php
class Car
{
private $color;
public function __construct()
{
$this->color = 'red';
}
public function color()
{
return $this->color;
}
}
class Ford extends Car
{
}
$ford = new Ford();
echo $ford->color(); // OUTPUTS 'red'
$reflection = new ReflectionClass($ford);
$properties = $reflection->getProperties();
foreach($properties as $property) {
echo $property->getName()."\n>";
}
$parent = $reflection->getParentClass();
$color = $parent->getProperty('color');
$color->setAccessible(true);
$color->setValue($ford,'blue');
echo $ford->color(); // OUTPUTS 'blue'
See it in action here: http://codepad.viper-7.com/R45LN0
See get_parent_class(): http://php.net/manual/en/function.get-parent-class.php
function getPrivateProperty(\ReflectionClass $class, $property)
{
if ($class->hasProperty($property)) {
return $class->getProperty($property);
}
if ($parent = $class->getParentClass()) {
return getPrivateProperty($parent, $property);
}
return null;
}
Here is the static version of the function I answered your other question with:
function getProperties($object) {
$properties = array();
try {
$rc = new \ReflectionClass($object);
do {
$rp = array();
/* #var $p \ReflectionProperty */
foreach ($rc->getProperties() as $p) {
$p->setAccessible(true);
$rp[$p->getName()] = $p->getValue($object);
}
$properties = array_merge($rp, $properties);
} while ($rc = $rc->getParentClass());
} catch (\ReflectionException $e) { }
return $properties;
}

Categories