Singleton class, multidimensional array unset element - php

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!

Related

Php: turning it into a recursive function

I have currently two classes.
the ArrayCompare class:
<?php
namespace App\Tools\RegexExtract;
class ArrayCompare
{
public function compare(Array $arrayToCompare)
{
$elementData = new ElementMetaData();
$metaData = $elementData->extract($arrayToCompare[0], [], $initial=true);
foreach ($arrayToCompare as $currentElement) {
$metaData = $elementData->extract($currentElement, $metaData);
}
return $metaData;
}
}
which uses the ElementMetaData class
<?php
/**
* A class for extracting meta data from an element.
*/
namespace App\Tools\RegexExtract;
class ElementMetaData
{
public function extract($element, $metaDataToCompare = [], $initial = false)
{
if ($initial == true) {
$this->isInteger($element) ? $returnMetaData['isInteger'] = $this->isInteger($element) : null;
$returnMetaData['length'] = $this->length($element);
}
else {
$returnMetaData=$metaDataToCompare;
if ($returnMetaData != []) {
if (isset ($returnMetaData['isInteger']) && !$this->isInteger($element)) {
unset($returnMetaData['isInteger']);
}
if (isset ($returnMetaData['length']) && $this->length($element) != $returnMetaData['length']) {
unset($returnMetaData['length']);
}
}
}
return $returnMetaData;
}
private function isInteger($element)
{
return is_int($element);
}
private function length($element)
{
return strlen($element);
}
}
the basic functionality is:
given I have an array
$arr=[1,2,3];
I want to get the "similarities" between ALL Elements. According to a an array i Predefine...so this would deliver this result:
$metaArray=['isInteger'=>true,'length'=>1];
and this would deliver just length as similarity:
$arr=[1,2,'D'];
$metaArray=['length'=>1];
While this array would deliver an empty result []
$arr=[1,2,'3D']; // result is [] since not all integers or not all of same length.
Now my solution does not use recursive functions...but I am sure it can be used somehow.
Also, I want to add more "criteria"....So "isEmailAdress", "beginswithA"....etc....and this would make my if statements a horror....so what is the best strategy/design pattern to follow here?
#deceze beat me to it by fair margin... but I'll still post my solution that works basically with the same principles.
abstract class abstractComparer
{
private $array;
private $result = true;
protected $name;
public function compareArray($array)
{
$current = null;
foreach ($array as $index => $value)
{
$this->result = $this->result && $this->compareValues($index, $current, $value);
$current = $value;
}
}
public function getResult()
{
return $this->result;
}
public function getName()
{
return $this->name;
}
public abstract function compareValues($index, $value1, $value2);
public abstract function getSuccessValue();
}
class intComparer extends abstractComparer
{
protected $name = "isInteger";
public function compareValues($index, $value1, $value2)
{
return is_int($value2);
}
public function getSuccessValue()
{
return true;
}
}
class lengthComparer extends abstractComparer
{
protected $name = "length";
protected $length = 0;
public function compareValues($index, $value1, $value2)
{
$this->length = strlen($value2);
return $index == 0 || strlen($value1) == $this->length;
}
public function getSuccessValue()
{
return $this->length;
}
}
And do the actual processing like this:
$temp = [1,2,3];
$comparers = [new intComparer(), new lengthComparer()];
$result = array();
foreach ($comparers as $comparer)
{
$comparer->compareArray($temp);
if ($comparer->getResult())
{
$result[$comparer->getName()] = $comparer->getSuccessValue();
}
}
//var_dump($result);
I don't see any need for recursion here, so I'll just make a suggestion for a design approach:
Implement each criterion as a class:
abstract class Criterion {
protected $valid = true;
abstract public function initialize($value);
abstract public function check($value);
public function isValid() {
return $this->valid;
}
}
class Length extends Criterion {
protected $length;
public function initialize($value) {
$this->length = strlen($value);
}
public function check($value) {
if ($this->length != strlen($value)) {
$this->valid = false;
}
}
}
You then make an array of all your criteria:
$criteria = [new Length, ...];
foreach ($criteria as $criterion) {
$criterion->initialize($values[0]);
}
And slowly whittle them down through your values:
foreach ($values as $value) {
foreach ($criteria as $criterion) {
$criterion->check($value);
}
}
$commonCriteria = array_filter($criteria, function (Criterion $criterion) {
return $criterion->isValid();
});

Get single value from an array

I have below array result
Array ( [0] => Item Object ( [name:protected] => My Super Cool Toy [price:protected] => 10.99 ) )
I need to get [name:protected] => My Super Cool Toy from this array.
Please tell me how to get it,
I will paste my classes below
class ShoppingCart
{
private $items = array();
private $n_items = 0;
function addItem( Item $item )
{
$this->items[] = $item;
$this->n_items = $this->n_items + 1;
print_r($this->items);
}
}
and
class Item {
protected $name;
protected $price;
public function __construct($name, $price) {
$this->name = $name;
$this->price = $price;
}
public function getName() {
echo "item is $this->name";
return $this->name;
}
public function getPrice() {
return $this->price;
}
}
and
require_once('AddingMachine.php');
require_once('item.php');
//$arrayofnumbers = array(100,200);
$objectname = new ShoppingCart();
$objectname->addItem(new Item('My Super Cool Toy', 10.99));
$obname = new Item($items,44);
$obname->getName();
Thanks
If I got it correctly, you got this array in ShoppingCart class, in method addItem, so to access it you just use corresponding getter method, e.g.:
$this->items[0]->getName();
You can try :
$objectname = new ShoppingCart();
$objectname->addItem(new Item('My Super Cool Toy', 10.99));
foreach ( $objectname->getItems() as $item ) {
echo $item->getName(), PHP_EOL;
}
Modified Class
class ShoppingCart {
private $items = array();
private $n_items = 0;
function addItem(Item $item) {
$this->items[] = $item;
$this->n_items = $this->n_items + 1;
}
function getItems($n = null) {
return $n === null ? $this->items : (isset($this->items[$n]) ? : $this->items[$n]);
}
}

Calling Method of array of objects?

How can I call methods from an array of objects (that hold an array of objects). I read: Get array with results of object method on each item in an array of objects in PHP but could not get it.
Here is my testcode: the first object holds attributes, then an object holds a record of the multiple attributes.
/*--------------------------------- */
class SqliteAttribute {
private $_fieldname = '';
private $_fieldvalue = '';
private $_type = 'TEXT';
private $_key = true;
function __construct($fieldname, $fieldvalue, $text, $key) {
$this->_fieldname = $fieldname;
$this->_fieldvalue = $fieldvalue;
$this->_text = $text;
$this->_key = $key;
}
function AsArray() {
$tempArray = array('fieldname' => $this->_fieldname,
'fieldvalue' => $this->_fieldvalue,
'type' => $this->_type,
'key' => $this->_key
);
return $tempArray;
}
}
/*--------------------------------- */
class SqliteRecord {
private $_attributes = array();
function __construct() {
}
function AddAttribute($fieldname, $fieldvalue, $text, $key) {
$attribute = new SqliteAttribute($fieldname, $fieldvalue, $text, $key);
$this->attributes[] = $attribute;
var_dump($this->_attributes); // shows it!
}
function AsArray() {
$temp_array = array();
var_dump($this->_attributes); // shows nothing
foreach ($this->_attributes as $key => $value) {
$temp_array[] = $value->AsArray();
}
return $temp_array;
}
}
And I call it like this
function updateFiles($files, $rootpath) {
$recordset = new SqliteRecordSet;
foreach ($files as $file) {
$record = new SqliteRecord;
$record->AddAttribute('Path', $file[0], 'TEXT', true);
print_r($record->AsArray()); // shows nothing
}
$recordset->insertIfNotExist_index();
}
$this->attributes vs $this->_attributes
you should always develop code with error reporting set to E_ALL and display_errors on. php would have notified you of your mistake here.

class implementing Iterators loops

I have a problem with implementing Iterator interface
Here is the code:
class User_Model_Users implements Iterator, Countable
{
protected $_count;
protected $_gateway;
protected $_resultSet;
public function __construct($results, $gateway)
{
$this->setGateway($gateway);
$this->_resultSet = $results;
}
public function setGateway(User_Model_UserGateway $gateway)
{
$this->_gateway = $gateway;
return $this;
}
public function getGateway()
{
return $this->_gateway;
}
public function count()
{
if (null === $this->_count) {
$this->_count = count($this->_resultSet);
}
return $this->_count;
}
public function current()
{
if ($this->_resultSet instanceof Iterator) {
$key = $this->_resultSet->key();
} else {
$key = key($this->_resultSet);
}
$result = $this->_resultSet [$key];
if (!$result instanceof User_Model_User) {
$gateway = $this->getGateway();
$result = $gateway->createUser($result);
$this->_resultSet [$key] = $result;
}
return $result;
}
public function key()
{
return key($this->_resultSet);
}
public function next()
{
return next($this->_resultSet);
}
public function rewind()
{
return reset($this->_resultSet);
}
public function valid()
{
return (bool) $this->current();
}
}
As a $result I provide Zend_Db_Table_Rowset but it can be also other object or array.
How can I fix this code so that I works in a foreach loop?
I don't get any errors as it is an infinite loop.
Wild guess (haven't really delved into the code):
Since your implementation of valid() is
public function valid()
{
return (bool) $this->current();
}
you should make sure that current() returns false when there are no more elements
public function current()
{
if ($this->_resultSet instanceof Iterator) {
$key = $this->_resultSet->key();
} else {
$key = key($this->_resultSet);
}
if ( is_null($key) ) { // could also be is_null($key)||false===$key, not sure...
return false;
}
$result = $this->_resultSet[$key];
if (!$result instanceof User_Model_User) {
$gateway = $this->getGateway();
$result = $gateway->createUser($result);
$this->_resultSet[$key] = $result;
}
return $result;
}
and btw: your function key() doesn't implement the instanceof Iterator case like current() does.
Test script:
<?php
class User_Model_Users implements Iterator, Countable
{
protected $_count;
protected $_gateway;
protected $_resultSet;
public function __construct($results, $gateway)
{
$this->setGateway($gateway);
$this->_resultSet = $results;
$this->_count = null;
}
public function setGateway(User_Model_UserGateway $gateway)
{
$this->_gateway = $gateway;
return $this;
}
public function getGateway()
{
return $this->_gateway;
}
public function count()
{
if ( is_null($this->_count) ) {
$this->_count = count($this->_resultSet);
}
return $this->_count;
}
public function current()
{
if ($this->_resultSet instanceof Iterator) {
$key = $this->_resultSet->key();
} else {
$key = key($this->_resultSet);
}
if ( is_null($key) ) {
return false;
}
$result = $this->_resultSet[$key];
if (!$result instanceof User_Model_User) {
$gateway = $this->getGateway();
$result = $gateway->createUser($result);
$this->_resultSet[$key] = $result;
}
return $result;
}
public function key()
{
return key($this->_resultSet);
}
public function next()
{
return next($this->_resultSet);
}
public function rewind()
{
return reset($this->_resultSet);
}
public function valid()
{
return (bool) $this->current();
}
}
class User_Model_User {
protected $x, $y;
public function __construct($x, $y) {
$this->x = $x;
$this->y = $y;
}
}
class User_Model_UserGateway {
protected $id;
public function __construct() {
$this->id = time();
}
public function createUser($x) {
echo "User_Model_UserGateway::createUser($x)\n";
return new User_Model_User($x, $this->id);
}
}
$a = array('a', 'b', 'c', 'd');
$users = new User_Model_Users($a, new User_Model_UserGateway);
foreach($users as $u) {
print_r($u);
}
prints
User_Model_UserGateway::createUser(a)
User_Model_User Object
(
[x:protected] => a
[y:protected] => 1311167311
)
User_Model_UserGateway::createUser(b)
User_Model_User Object
(
[x:protected] => b
[y:protected] => 1311167311
)
User_Model_UserGateway::createUser(c)
User_Model_User Object
(
[x:protected] => c
[y:protected] => 1311167311
)
User_Model_UserGateway::createUser(d)
User_Model_User Object
(
[x:protected] => d
[y:protected] => 1311167311
)

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