PHP static method recursive - php

Is it possible to do a recursion on a static method?
class Helpers {
public static function objectToArray($obj) {
if (is_object($obj)) {
$obj = get_object_vars($obj);
}
if (is_array($obj)) {
return array_map(__FUNCTION__, $obj);
}
else {
return $obj;
}
}
}
I'm getting this error when executed:
Severity: Warning
Message: array_map() expects parameter 1 to be a valid callback, function 'objectToArray' not found or invalid function name.
Thanks!

You can recursively call a static method. The
following code, for example, will work fine:
<?php
class MyClass{
public static function test($count)
{
if ($count < 10) {
$count++;
self::test($count);
echo $count;
}
}
}
MyClass::test(0);

Try this
return array_map(['Helpers', 'objectToArray'], $obj);
array_map permit callable type.
You could try it with magic constants
return array_map([__CLASS__, __METHOD__], $obj);
Or using self
return array_map([self, __METHOD__], $obj);

You should use:
return array_map('self::objectToArray', $obj);
// or
return array_map(array(self, 'objectToArray'), $obj);
Provide an alternative solution for you (encode the object to a json string, then decode it to an array):
class Helpers {
public static function objectToArray($obj) {
return json_decode(json_encode($obj), true);
}
}

Related

Run method chain from a string value

I have a question about getting value from running a method from a string. While I am able to handle a single method call from a string I am curious how to call a chain of methods from a string.
For example. $project is an Object.
$method1 = "name";
$project->$method1; // It shows the valid results
$method2 = "get()->first()->name";
$project->get()->first()-name; // It shows the valid results
$project->$method2; // get a null result
Please help to find a way to make the $method2 work. And what happen if I have params inside those methods?
The reason here is I have made an array of customized methods. It can be run line by line, but I am thinking of a way to turn them into a loop, so it's more efficient. Put the methods in to a file then get values by looping to them.
Array = ["getvalue1()", "getvalue2()",...."getValuen()->anotherMethod()->value"]
Thanks,
If you want nested try something like this:
private function callMethodChain($model, $methodChain)
{
return array_reduce(explode('->', $methodChain), function($model, $method) {
return $model->$method;
}, $model);
}
This will go through a chain of method calls as your described. If some of the chain (the last piece) is a property I think I once rigged up the following to handle it:
protected function callMethodChain($model, $methodChain)
{
return array_reduce(explode('->', $methodChain), function($model, $method) {
try {
return $model->$method;
} catch (Exception $e) {
return $model->$method();
}
}, $model);
}
If you want to add params try replacing $model->method with:
call_user_func_array(
array($project, 'your_method'),
$params
);
Try this approach:
$method1 = 'name';
$project->{$method1}();
Run method from a string value
Use call_user_func() and call_user_func_array().
call_user_func_array() suits good if you are passing parameters
call_user_func_array(
array($project, 'your_method'),
$params
);
Chain function
function chain_fun($chain,$object)
{
return array_reduce(explode('->', $chain), function ($obj, $method) {
if(preg_match('/[()]/',$method)){
$method=trim($method,'()');
return $obj->$method();
}
return $obj->$method;
}, $object);
}
Here is test
akshay#db-3325:/tmp$ cat test.php
<?php
class Testclass
{
private $str;
function __construct()
{
$this->str = new StdClass;
}
function addA()
{
$this->str->a='A';
return $this;
}
function addB()
{
$this->str->b='B';
return $this;
}
function get()
{
return $this->str;
}
}
function chain_fun($chain,$object)
{
return array_reduce(explode('->', $chain), function ($obj, $method) {
if(preg_match('/[()]/',$method)){
$method=trim($method,'()');
return $obj->$method();
}
return $obj->$method;
}, $object);
}
$object = new Testclass();
// Output 1
print_r(chain_fun("addA()->addB()->get()", $object));
// Output 2
echo chain_fun("addA()->addB()->get()->a", $object);
?>
Output
akshay#db-3325:/tmp$ php test.php
stdClass Object
(
[a] => A
[b] => B
)
A

How to call a callback function in a PHP class

I want to use array_filter to remove those items in an array whose value is equal to a specific character like '.' . To do, so I used the following code but I don't know how to pass the callback function to array_filter:
class Myclass(){
private function isPunc($var){
if($var=='.'){
return TRUE;
}else{
return FALSE;
}
public function myfunction($arr){
$arr = array_filter($arr,"isPunc");
}
}
Any idea how to solve this problem?
class Myclass(){
private function isPunc($var) {
if ($var=='.') {
return TRUE;
} else {
return FALSE;
}
}
public function myfunction($arr) {
$arr = array_filter($arr, array($this,'isPunc'));
}
}
use $arr = array_filter($arr, array($this, 'isPunc'));
array_filter() expects a Callable. This is an special internal type in PHP that can be on of four things:
a string with function name
an array with an object and method name as elements
an anonymous function
a functor (an object that implements __invoke)
In your case the second variant should work:
class FilterIsDot {
private function accept($element) {
if($element == '.'){
return TRUE;
}else{
return FALSE;
}
}
public function filter($array) {
return array_filter(
$array, array($this, 'accept')
);
}
}
$in = array('.', 'foo');
$filter = new FilterIsDot();
var_dump($filter->filter($in));
I would suggest a different approach avoiding array_filter(). SPL contains a FilterIterator class. You can extends this class:
class FilterIsDot extends FilterIterator {
public function __construct($arrayOrIterator) {
parent::__construct(
is_array($arrayOrIterator)
? new ArrayIterator($arrayOrIterator)
: $arrayOrIterator
);
}
public function accept() {
if($this->current() == '.') {
return TRUE;
}else{
return FALSE;
}
}
}
$in = array('.', 'foo');
$filter = new FilterIsDot($in);
var_dump(iterator_to_array($filter));
In this case the filter works on the fly. It is only used if the elements are actually accessed.

Incurring the resource from another class, the resource table

I am looking for a way to load an array from another class, as in the Kohana Framework. But I fail to get the message Notice: Undefined variable: tab1
<?php
class A {
private $tab1 = array('raz'=>true, 'dwa'=>false);
private $tab2 = array('trzy'=>false, 'cztery'=>true);
public function config($var) {
return $$var;
}
}
class B {
public function get() {
$ob = new A;
$tab = $ob->config('tab1');
//unset($ob)
return $tab;
}
}
$ob=new B;
$tab = $ob->get();
print_r($tab);
Try this:
public function config($var){
return $this->$var;
}
return $this->$var;
is correct. Use it instead of
return $$var;

PHP array_key_exists() and SPL ArrayAccess interface: not compatible?

I wrote a simple collection class so that I can store my arrays in objects:
class App_Collection implements ArrayAccess, IteratorAggregate, Countable
{
public $data = array();
public function count()
{
return count($this->data);
}
public function offsetExists($offset)
{
return (isset($this->data[$offset]));
}
public function offsetGet($offset)
{
if ($this->offsetExists($offset))
{
return $this->data[$offset];
}
return false;
}
public function offsetSet($offset, $value)
{
if ($offset)
{
$this->data[$offset] = $value;
}
else
{
$this->data[] = $value;
}
}
public function offsetUnset($offset)
{
unset($this->data[$offset]);
}
public function getIterator()
{
return new ArrayIterator($this->data);
}
}
Problem: when calling array_key_exists() on this object, it always returns "false" as it seems this function is not being handled by the SPL. Is there any way around this?
Proof of concept:
$collection = new App_Collection();
$collection['foo'] = 'bar';
// EXPECTED return value: bool(true)
// REAL return value: bool(false)
var_dump(array_key_exists('foo', $collection));
This is a known issue which might be addressed in PHP6. Until then, use isset() or ArrayAccess::offsetExists().

Custom foreach results for dynamic proxy class - magic methods?

I need to serialize a proxy class. The class uses __set and __get to store values in an array. I want the serialization to look like it is just a flat object. In other words, my class looks like:
class Proxy
{
public $data = array();
public function __get($name)
{
return $data[$name]
}
}
and I want a foreach loop to return all the keys and values in $data, when I say:
foreach($myProxy as $key)
Is this possible?
class Proxy implements IteratorAggregate
{
public $data = array();
public function __get($name)
{
return $data[$name];
}
public function getIterator()
{
$o = new ArrayObject($this->data);
return $o->getIterator();
}
}
$p = new Proxy();
$p->data = array(2, 4, 6);
foreach ($p as $v)
{
echo $v;
}
Output is: 246.
See Object Iteration in the PHP docs for more details.
You want to implement the SPL iterator interface
Something like this:
class Proxy implements Iterator
{
public $data = array();
public function __get($name)
{
return $data[$name]
}
function rewind()
{
reset($this->data);
$this->valid = true;
}
function current()
{
return current($this->data)
}
function key()
{
return key($this->data)
}
function next() {
next($this->data);
}
function valid()
{
return key($this->data) !== null;
}
}

Categories