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];
}
Related
I am trying to remove irrelevant data from a multidimensional array.
The array is looking like this:
[6] => Array
(
[710C27E0-822A-4513-9D44-D97E929484A9] => Array
(
[documents] => Array
(
[0] => error message
)
)
)
And i am using the following code:
<?php
class report {
private static $instance;
private $data = array();
private function __construct() { }
private function __clone() { }
public function __destruct() { }
public static function singleton() {
if (!isset(self::$instance))
self::$instance = new self();
return self::$instance;
}
public function check() {
foreach($this->data as $key => &$values) {
foreach($values as $k => &$value) {
/* some checks */
if($return != null)
$values[$return] = $values[$k];
unset($values[$k]);
}
if(sizeof($values) == 0)
unset($this->data[$key];
}
}
public function __toString() {
print_r($this->data);
return '';
}
}
When i replace upper check function by the following code it is working, but i am looking for some better/cleaner and especially faster solution.
public function check() {
$_data = json_encode($this->data);
$data = json_decode($_data);
foreach($data as $key => &$values) {
foreach($values as $k => &$value) {
/* some checks */
if($return != null)
$values->$return = $values->$k;
unset($values->$k);
}
}
$this->data = $data;
}
SOLVED but not understanding it..
public function log($id, $guid, $job, $message) {
$this->data[$id][$guid][$job][] = $message;
}
when i var_dump($guid) it returns:
string(36) "710C27E0-822A-4513-9D44-D97E929484A9"
now i did a string cast:
var_dump((string)$guid);
returning:
string(36) "710C27E0-822A-4513-9D44-D97E929484A9"
but
$this->data[$id][(string)$guid][$job][] = $message;
works!
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
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));
I have a class, that actually operates over a complicated array to make the manipulation more simple. The format of original array looks like this:
array(
array(
"name" =>"foo",
"type" =>8, //The array is NBT format and 8 stands for string
"value" =>"somevalue"
)
}
The class takes array like above as constructor:
class NBT_traverser implements ArrayAccess {
function __construct(&$array) {
$this->array = $array;
}
}
Then, this is how the members are accessed:
$parser = new NBT_traverser($somearray);
echo $parser["foo"]; //"somevalue"
When I print_R the class, I get the list of its values and the original complicated array. Like this:
object(NBT_traverser)#2 (1) {
["nbt":"NBT_traverser":private]=> &array(1) {
/*Tons of ugly array contents*/
}
Instead, I'd like to get this like the output of print_r:
array(
"foo" => "somevalue"
)
Is it possible to trick the print_r to do this? Current behavior makes it harder to debug with the class, than without it.
Of course, I can write my own method to print it, but I want to make the usage more simple for the users of the class. Instead, I wanted to give print_R something, that It will print as array.
You should not have issues if you are extending ArrayAccess just write a method to get your values
Example
$random = range("A", "F");
$array = array_combine($random, $random);
$parser = new NBT_traverser($array);
echo $parser->getPrint();
Output
Array
(
[A] => A
[B] => B
[C] => C
[D] => D
[E] => E
[F] => F
)
Class Used
class NBT_traverser implements ArrayAccess {
private $used; // you don't want this
protected $ugly = array(); // you don't want this
public $error = 0202; // you don't want this
private $array = array(); // you want this
function __construct(&$array) {
$this->array = $array;
}
function getPrint() {
return print_r($this->array, true);
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->array[] = $value;
} else {
$this->array[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->array[$offset]);
}
public function offsetUnset($offset) {
unset($this->array[$offset]);
}
public function offsetGet($offset) {
return isset($this->array[$offset]) ? $this->array[$offset] : null;
}
}
You could use the __toString function in your class
class Test
{
private $_array = array();
public function __toString()
{
return print_r($this->_array, true);
}
}
And then just echo out your class
$test = new Test();
echo $test;
I think this would print out your array as you want it to be?
Array
(
)
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