I have a ReflectionProperty object using the following code:
$service = new \ReflectionClass($this);
$properties = $service->getProperties();
$property = $properties[0];
I want to get the ReflectionObject object from the $property variable to get some extra information about the property (like what is its class and which classes is its class inherited from). How can I achieve this?
e.g.
class A {
/**
* #var \Utils\WebService
*/
public $prop;
}
now, I get the ReflectionClass (which actually refers to 'A') and I need to get the ReflectionClass/ReflectionObject for the $prop property. I need to later check what is the type of $prop and what supertypes it extends.
Thanks
class WebCrawler {
}
class WebService extends WebCrawler {
}
class A {
/**
* #var \WebService
*/
public $prop;
public $variable = 'hello';
function __construct()
{
$this->prop = new WebService();
}
}
// reflection
$obj = new A();
$reflectionObject = new \ReflectionObject($obj);
// get all public and protected properties
$properties = $reflectionObject->getProperties(\ReflectionProperty::IS_PUBLIC);
$properties = \array_merge($properties, $reflectionObject->getProperties(\ReflectionProperty::IS_PROTECTED));
\var_dump($properties);
// create the array similar to what you asked for
$data = [];
foreach ($properties as $property) {
$name = $property->name;
$data[$name] = $obj->{$name};
}
\var_dump($data);
// get info which class was inherited to the class defined in A::prop property
$reflectedObjectFromProperty = new \ReflectionObject($data['prop']);
\var_dump($reflectedObjectFromProperty->getParentClass());
Related
Im trying to create a class extending GearmanClient so i can centralize and use gearman across my app according to my own specifications. One of the reasons im doing my own class is to store easily failed tasks into a database so they can be later processed again.
Im getting a basic error
Warning: GearmanClient::runTasks():
_client_run_task(GEARMAN_NO_SERVERS) no servers added -> libgearman/run.cc:66 in /var/www/html/app/forecast/Forecast.php on
line 37
<?php
namespace app\service;
use helpers\Config_helper;
use \GearmanClient;
class Gearman_service extends GearmanClient
{
public $client;
private $servers = array();
private $tasks = array();
private $completedTasks = array();
private $failedTasks = array();
private $maxRetryAttempts;
public function __construct()
{
$this->client = new GearmanClient();
$this->servers = Config_helper::get_config_option('gearman_servers');
$this->maxRetryAttempts = Config_helper::get_config_option('gearman_retry_attempts');
$this->initialize();
}
protected function initialize()
{
foreach($this->servers as $key => $value):
$this->client->addServer($value[0],$value[1]);
endforeach;
}
}
I must assume something is wrong with this implementation but i would like to know why.
The Config_helper::get_config_option('gearman_servers'); is retrieving correctly my list of servers.
This is my Forecast class
<?php
namespace app\forecast;
use app\service\Gearman_service;
use helpers\Config_helper;
use helpers\Urlrequest_helper;
use app\warehouse\models\Client_time_forecast;
abstract class Forecast
{
public $coordinates = array(); # set of coordinates
public $servers = array();
public $variables = array();
public $url = array();
public $prevision;
public $client;
public $gearmanclient;
public function __construct()
{
$this->servers = Config_helper::get_config_option('forecast_servers');
$this->variables = Config_helper::get_config_option('surface_variables');
$this->prevision = Config_helper::get_config_option('forecast_prevision');
$this->gearmanclient = new Gearman_service();
}
public function storeResults()
{
$this->gearmanclient->setCompleteCallback(array($this, 'requestComplete'));
foreach($this->url as $key => $value):
$this->gearmanclient->addTask('request_forecast', serialize($value[0]));
endforeach;
$this->gearmanclient->runTasks(); // **line 37**
}
/**
* [requestComplete store request results in cassandra db]
* #param \GearmanTask $task [description]
* #return [boolean]
*/
public function requestComplete(\GearmanTask $task)
{
$persistent = new Client_time_forecast($this->client, unserialize($task->data()));
$persistent->storeData();
}
}
Anyone can share me a light on this?
Thank you!
As suspected the cause of the problem is that you are mixing inheritance and composition. You extended the GearmanClient class and at the same time you are creating a new instance of the GearmanClient class in the constructor and configuring this new instance in method initialize.
class Gearman_service extends GearmanClient
{
public $client;
// other properties
public function __construct()
{
$this->client = new GearmanClient();
// more code
$this->initialize();
}
You could change the line 37 and all other calls to GermanClient public methods to call the instance initiated in constructor and do not extend GearmanClient class.
$this->gearmanclient->client->runTasks();
However it would be better to change visibility of the property Gearman_service::client to private and implement GeamanClient class public interface.
class Gearman_service extends GearmanClient
{
private $client;
// constructor etc
public function addTask($name, $workload, $context = null, $unique = "")
{
return $this->client->addTask($name, $workload, $context, $unique);
}
If you do so the line 37 should stay as it is.
Alternatively you could opt for inheritance. In that case you would need to remove public property client, do not create a new instance of the GeamanClient class in the constructor and change initialize methods.
protected function initialize()
{
foreach($this->servers as $key => $value):
$this->addServer($value[0],$value[1]);
endforeach;
}
In this case as well you don't need to change the line 37 nor any other calls GeamanClient class public methods.
Is there any way I can set up PHP objects so that when I try to convert them to JSON, all of their protected properties will be shown?
I have read other answers suggesting I add a toJson() function to the object, but that may not really help me a great lot. In most cases, I have an array of objects and I perform the encode on the array itself.
$array = [
$object1, $object2, $object3, 5, 'string', $object4
];
return json_encode($array);
Yes, I can loop through this array and call toJson() on every element that has such method, but that just doesn't seem right. Is there a way I can use magic methods to achieve this?
You can implement the JsonSerializable interface in your classes so you have full control over how it is going to be serialized. You could also create a Trait to prevent copy pasting the serializing method:
<?php
trait JsonSerializer {
public function jsonSerialize()
{
return get_object_vars($this);
}
}
class Foo implements \JsonSerializable
{
protected $foo = 'bar';
use JsonSerializer;
}
class Bar implements \JsonSerializable
{
protected $bar = 'baz';
use JsonSerializer;
}
$foo = new Foo;
$bar = new Bar;
var_dump(json_encode([$foo, $bar]));
Alternatively you could use reflection to do what you want:
<?php
class Foo
{
protected $foo = 'bar';
}
class Bar
{
protected $bar = 'baz';
}
$foo = new Foo;
$bar = new Bar;
class Seriailzer
{
public function serialize($toJson)
{
$data = [];
foreach ($toJson as $item) {
$data[] = $this->serializeItem($item);
}
return json_encode($data);
}
private function serializeItem($item)
{
if (!is_object($item)) {
return $item;
}
return $this->getProperties($item);
}
private function getProperties($obj)
{
$rc = new ReflectionClass($obj);
return $rc->getProperties();
}
}
$serializer = new Seriailzer();
var_dump($serializer->serialize([$foo, $bar]));
What is the proper way to do this:
// child
class B extends A {
function __construct() {
$this->object = new B; /// (or `new self` ?)
}
}
// parent
class A {
protected $object;
private static function {
$object = $this->object;
// use the new instance of $object
}
}
When I try this in code, I get this error:
Fatal error: Using $this when not in object context What am I doing wrong? (this is referring to Class A instance)
You cannot use $this in a static method; $this can only be used in an instantiated object.
you will have to change $object to a static and call it using self::$object
class B extends A {
function __construct() {
self::$object = new B;
}
}
// parent
class A {
static protected $object;
private static function doSomething(){
$object = self::$object;
// use the new instance of $object
}
}
You can't use $this to refer to the object in a static method, so you have to change it up a bit. Make object a protected static member.
class A {
protected static $object;
private static function() {
$object = self::$object;
// use the new instance of $object
}
}
I have a static class Foo (this isn't a real class, so static fields are just for example)
class Foo{
public static $name = "foo";
public static $age = "18";
public static $city = "Boston";
}
In my code I want to build an array of all the public static properties and their current values.
Is there a quick/easy way anyone can suggest to do this without instantiating a Foo?
Use a ReflectionClass instance like this to get an array of the property names and values:
$class = new ReflectionClass('Foo');
$staticProperties = $class->getStaticProperties();
foreach ($staticProperties as $propertyName => $value) {
// Your code here
}
Use the Reflection
<?php
require_once "Foo.php";
$reflection = new ReflectionClass("Foo");
$staticProperties = $reflection->getStaticProperties();
print_r($staticProperties)
http://php.net/manual/en/reflectionclass.getstaticproperties.php
http://ca2.php.net/manual/en/reflectionclass.getstaticpropertyvalue.php
Let's say I have this class:
class Example {
public static $FOO = array('id'=>'foo', 'length'=>23, 'height'=>34.2);
public static $BAR = array('id'=>'bar', 'length'=>22.5, 'height'=>96.223);
}
How could I use reflection to get a list of the static fields? (Something like array('$FOO', '$BAR')?)
You'll want to use [ReflectionClass][1]. The getProperties() function will return an array of ReflectionProperty objects. The ReflectionProperty object have a isStatic() method which will tell you whether the property is static or not and a getName() method that return the name.
Example:
<?php
class Example {
public static $FOO = array('id'=>'foo', 'length'=>23, 'height'=>34.2);
public static $BAR = array('id'=>'bar', 'length'=>22.5, 'height'=>96.223);
}
$reflection = new ReflectionClass('Example');
$properties = $reflection->getProperties();
$static = array();
if ( ! empty($properties) )
foreach ( $properties as $property )
if ( $property->isStatic() )
$static[] = $property->getName();
print_r($static);