How to get public properties of a class? - php

I can't use simply get_class_vars() because I need it to work with PHP version earlier than 5.0.3 (see http://pl.php.net/get_class_vars Changelog)
Alternatively: How can I check if property is public?

This is possible by using reflection.
<?php
class Foo {
public $alpha = 1;
protected $beta = 2;
private $gamma = 3;
}
$ref = new ReflectionClass('Foo');
print_r($ref->getProperties(ReflectionProperty::IS_PUBLIC));
the result is:
Array
(
[0] => ReflectionProperty Object
(
[name] => alpha
[class] => Foo
)
)

Or you can do this:
$getPublicProperties = create_function('$object', 'return get_object_vars($object);');
var_dump($getPublicProperties($this));

You can make your class implement the IteratorAggregate interface
class Test implements IteratorAggregate
{
public PublicVar01 = "Value01";
public PublicVar02 = "Value02";
protected ProtectedVar;
private PrivateVar;
public function getIterator()
{
return new ArrayIterator($this);
}
}
$t = new Test()
foreach ($t as $key => $value)
{
echo $key." = ".$value."<br>";
}
This will output:
PublicVar01 = Value01
PublicVar02 = Value02

Related

PHP: Get list of private fields of a class (not instance!)

How can I iterate the private fields of a class without having an instance of it but just the class name?
get_object_vars requires an existing instance.
Using: ReflectionClass
you can simply do:
class Foo
{
public $public = 1;
protected $protected = 2;
private $private = 3;
}
$refClass = new \ReflectionClass('Foo');
foreach ($refClass->getProperties() as $refProperty) {
if ($refProperty->isPrivate()) {
echo $refProperty->getName(), "\n";
}
}
or hide the implementation using a utility function/method:
/**
* #param string $class
* #return \ReflectionProperty[]
*/
function getPrivateProperties($class)
{
$result = [];
$refClass = new \ReflectionClass($class);
foreach ($refClass->getProperties() as $refProperty) {
if ($refProperty->isPrivate()) {
$result[] = $refProperty;
}
}
return $result;
}
print_r(getPrivateProperties('Foo'));
// Array
// (
// [0] => ReflectionProperty Object
// (
// [name] => private
// [class] => Foo
// )
//
// )

Cloning object based on content in PHP

I seem to be going round in circles here but i have a situation where I when reading some objects i may come across some that contain an array. When this happens i wish to produce new objects based upon the array for example
sourceObject(namespace\className)
protected '_var1' => array('value1', 'value2')
protected '_var2' => string 'variable 2'
Should become
childObject1(namespace\className)
protected '_var1' => string 'value1'
protected '_var2' => string 'variable2'
childObject2(namespace\className)
protected '_var1' => string 'value2'
protected '_var2' => string 'variable2'
However due to not quite getting my head around it my clones always end up with the same content (sometimes both are value1 sometimes value2)
You could create a method like the following one:
trait classSplitClone
{
public function splitClone($name)
{
if (!is_array($this->$name)) {
return [$this];
}
$objs = [];
$values = $this->$name;
$c = 0;
foreach ($values as $value) {
$objs[] = $c ? clone $this : $this;
$objs[$c]->$name = $value;
$c++;
}
return $objs;
}
}
and then use it in your class(es) as a trait
class className
{
use classSplitClone;
protected $var1;
protected $var2;
function __construct($var1, $var2)
{
$this->var1 = $var1;
$this->var2 = $var2;
}
}
An example could look like:
$obj = new className(['value1', 'value2'], 'variable 2');
print_r($obj->splitClone('var1'));
Yielding the following results:
Array
(
[0] => className Object
(
[var1:protected] => value1
[var2:protected] => variable 2
)
[1] => className Object
(
[var1:protected] => value2
[var2:protected] => variable 2
)
)
Hope this helps. Alterantively you can access private and protected members also via ReflectionObject.
The full example code (Demo):
<?php
/**
* #link http://stackoverflow.com/a/24110513/367456
*/
/**
* Class classSplitClone
*/
trait classSplitClone
{
public function splitClone($name)
{
if (!is_array($this->$name)) {
return [$this];
}
$objs = [];
$values = $this->$name;
$c = 0;
foreach ($values as $value) {
$objs[] = $c ? clone $this : $this;
$objs[$c]->$name = $value;
$c++;
}
return $objs;
}
}
/**
* Class className
*/
class className
{
use classSplitClone;
protected $var1;
protected $var2;
function __construct($var1, $var2)
{
$this->var1 = $var1;
$this->var2 = $var2;
}
}
/*
* Example
*/
$obj = new className(['value1', 'value2'], 'variable 2');
print_r($obj->splitClone('var1'));

How to create instances with strings in php

I have a class called the 'analyst' and he has many 'analysers'. The analysers go looking for certain patterns in a given input.
For now, I create the instances of the 'analysers' in the constructor function of the anaylser like this:
<?php
class analyser {
protected $analysers = array();
public function __construct() {
$analyser1 = new Analyser1();
$this->analysers[] = $analyser1;
$analyser2 = new Analyser1();
$this->analysers[] = $analyser2;
...
}
This works for a limited amount of analysers but I want to create an array ('analyser1', 'analyser2', ...) that will be used in a loop to create all the needed instances. Is this possible or do I need to create every instance manually?
public function __construct() {
foreach ($names as $analyser){
$instance = new $analyser();
$this->analysers[] = $instance;
}
How can i do this ?
This should be straightforward - furthermore you could use nested associative array data to add some initial properties to each object, for example, you might want to give each object a name property:
<?php
class Analyser1
{
protected $name;
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
$analyserData = [
['name' => 'analyser1'],
['name' => 'analyser2'],
['name' => 'analyser3'],
];
$analysers = [];
foreach ($analyserData as $data) {
$obj = new Analyser1();
$name = $data['name'];
$obj->setName($name);
$analysers[$name] = $obj;
echo 'created ' . $obj->getName() . PHP_EOL;
}
print_r($analysers);
Yields:
created analyser1
created analyser2
created analyser3
Array
(
[analyser1] => Analyser1 Object
(
[name:protected] => analyser1
)
[analyser2] => Analyser1 Object
(
[name:protected] => analyser2
)
[analyser3] => Analyser1 Object
(
[name:protected] => analyser3
)
)
Example here: https://eval.in/133225
Hope this helps! :)
You can use this simple code:
public function __construct() {
for ($i=1; $i<=10; $i++){
// if you want associative array, you should use this part
$key = 'analyser' . $i;
$this->analysers[$key] = new Analyser1();
}
}
And it would create 10 instances of class Analyser1 in array $this->analysers

How can I get all the public property values of a 'last descendant' object in php?

The code below makes this easier to explain :
<?php
class a
{
public $dog = 'woof';
public $cat = 'miaow';
private $zebra = '??';
}
class b extends a
{
protected $snake = 'hiss';
public $owl = 'hoot';
public $bird = 'tweet';
}
$test = new b();
print_r(get_object_vars($test));
Currently this returns:
Array
(
[owl] => hoot
[bird] => tweet
[dog] => woof
[cat] => miaow
)
what can I do to find properties that were only defined or set in class b (eg just owl and bird)?
Use ReflectionObject for this:
$test = new b();
$props = array();
$class = new ReflectionObject($test);
foreach($class->getProperties() as $p) {
if($p->getDeclaringClass()->name === 'b') {
$p->setAccessible(TRUE);
$props[$p->name] = $p->getValue($test);
}
}
print_r($props);
Output:
Array
(
[snake] => hiss
[owl] => hoot
[bird] => tweet
)
getProperties() will return all properties of the class. I'm using $p->getDeclaringClass() afterwards to check if the declaring class is b
Additionally this can be generalized to a function:
function get_declared_object_vars($object) {
$props = array();
$class = new ReflectionObject($object);
foreach($class->getProperties() as $p) {
$p->setAccessible(TRUE);
if($p->getDeclaringClass()->name === get_class($object)) {
$props[$p->name] = $p->getValue($object);
}
}
return $props;
}
print_r(get_declared_object_vars($test));

using the magic __set() method with 2D arrays

If I have the following registry class:
Class registry
{
private $_vars;
public function __construct()
{
$this->_vars = array();
}
public function __set($key, $val)
{
$this->_vars[$key] = $val;
}
public function __get($key)
{
if (isset($this->_vars[$key]))
return $this->_vars[$key];
}
public function printAll()
{
print "<pre>".print_r($this->_vars,true)."</pre>";
}
}
$reg = new registry();
$reg->arr = array(1,2,3);
$reg->arr = array_merge($reg->arr,array(4));
$reg->printAll();
Would there be an easier way to push a new item onto the 'arr' array?
This code: 'array[] = item' doesn't work with the magic set method, and I couldn't find any useful info with google. Thanks for your time!
If you have:
$reg = new registry();
$reg->arr = array(1,2,3);
$reg->arr = 4;
And you're expecting:
Array
(
[arr] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
)
All you need to do is update your __set method to:
public function __set($key, $val){
if(!array_key_exists($key, $this->_vars)){
$this->_vars[$key] = array();
}
$this->_vars[$key] = array_merge($this->_vars[$key], (array)$val);
}
You need to alter the definition of __get() so that it returns by reference:
public function &__get($key) {
return $this->_vars[$key];
}

Categories