PHP Dynamic Method Chaining - php

How can I chain multiple methods together without knowing how many there will be? For instance how can I call this addMultiLink method more than once like a loop?
(new EntryField('products'))->addMultiLink($product_ids[0])
Basically I would want the result to be like this:
(new EntryField('products'))->addMultiLink($product_ids[0])->addMultiLink($product_ids[1])->addMultiLink($product_ids[2])

In your addMultiLink return $this:
public function addMultiLink($argument)
{
// your code here
return $this;
}
But as I can see you pass elements of array in your function per call.
Maybe it's better to rewrite addMultiLink and consider it's argument as array? Or check if it is array or some integer value:
public function addMultiLink($argument)
{
if (is_array($argument)) {
// do a foreach loop for example
} else {
// do something else
}
}

$product_entry_field = (new EntryField('products'));
foreach($product_ids as $product_id) {
$product_entry_field->addMultiLink($product_id);
}

Related

php recursive function return before end

i have got the following recursive function:
private function myRecursiveFunction()
{
$results = [];
//stuff related to $results
...
if(!$done){
.....
$this->myRecursiveFunction();
}
return $results;
}
when i do var_dump($results) inside function i got the all array results
but when i call the function from another one i will got only the first element in $results array.
public function myFunction()
{
$results = $this->myRecursiveFunction();
}
I am not 100% sure what you wish to accomplish here, but recursive functions usually send their "workload" all the way to the innermost function, then the results are "added" on each other at the way back. If this is indeed what you want, you may need to change your code to something like this:
private function myRecursiveFunction()
{
$results = [];
//stuff related to $results
...
if(!$done){
.....
// Add the computed results of the recursive call to our data stack
$results[] = $this->myRecursiveFunction();
}
// Return the entire result array
return $results;
}

How to filter all returned values from methods in class

I inherited this PHP project. I've got one class which contains maybe 20 different methods, most of which return values. I'd like to filter every value returned by methods in this class. Is there a simple and elegant way to do this, or must I wrap every value in a filter method before it is returned?
The class looks like this:
class db_ops
{
// ...
public function get_var($query) {
// ...
return $values;
}
public function get_name($query) {
// ...
return $name;
}
// ...
}
I've used a sort of wrapper class to do something like this before. Here's a generic example, just to show how it works. If you like this idea you should be able implement your own along these lines.
class FilteredExample
{
private $example;
function __construct($example)
{
$this->example = $example;
}
public function __call($name, $arguments)
{
if (method_exists($this->example, $name)) {
$result = call_user_func_array([$this->example, $name], $arguments);
if (is_string($result)) {
return "$result filtered";
} elseif (is_array($result)) {
return array_map(function($item){ return "$item filtered"; }, $result);
} else {
return $result;
}
} else {
throw new BadMethodCallException("Method '$name' not found", 1);
}
}
}
You inject the object whose methods you want to filter in the constructor, and then use the __call() magic method so that you can call all of the original object's methods. With method_exists, you can validate any called method and throw an exception if it doesn't exist, just like you'd get if you called it on the original object. If it does exist, then you can call it with call_user_func_array, filter the result, and return it.
I added a little section to show that you can handle different result types, or just return the unmodified result if it's not a certain type. You obviously wouldn't need to do this if all your original object's methods return the same type.
Here is an example of how you could use it based on the example class from your question:
$dbOps = new db_ops;
$filteredDbOps = new FilteredExample($dbOps);
$result = $filteredDbOps->get_var('something');

Return 2 things from a function

I have a function that returns a multidimensional array, but I also need to return a single value. I am currently using the single value via the global keyword, so I can modify it inside the function.
But I'm wondering if there is another/better way to return 2 values from a function?
Current (pseudo) code:
global $iNumber;
$arrResult;
{do some calculations and queries}
$iNumber = 73;
return $arrResult;
The function that called this function can use the array of arrays, and also the global variable which has been updated to 73.
But is there another/better way to combine or pass these two different values?
You can do it in two ways: to return an array or an object.
Array solution:
function calculate(...) {
//do some stuff
return ['result' => $arrResult, 'iNumber' => $iNumber];
}
Object solution:
function calculate(...) {
//do some stuff
$object = new stdClass();
$object->result = $arrResult;
$object->iNumber = $iNumber;
return $object;
}
stdClass is just an example and you can create your own class for this purpose.
You can make a class and use a class variable.
Something like this:
class Test
{
public $iNumber;
function __construct()
{
# code...
}
public function yourCal()
{
// you calculations
$this->setNumber(73);
return $arrayOfArrays;
}
public function getNumber()
{
return $this->iNumber;
}
public function setNumber($var)
{
$this->iNumber = $var;
}
}
// Use the class in another php file
include 'Test.php';
$test = new Test();
// do calculations
$arrayOfArrays = $test->yourCal();
// get the number
$iNumber = $test->getNumber();
echo $iNumber; // returns 73
print_r($arrayOfArrays); // print your array

ResultSet in Zend Framework 2 does not work with toArray()

I thought that I would be able to use toArray() on my Zend resultset, but I find that using toArray() fails with the message:
Rows as part of this DataSource, with type object cannot be cast to an array
What I thought would work was something like
return new JsonModel($collections->toArray());
But that fails with the above error message.
Here is the Collection, a small class
class Collection
{
public $collectionID;
public $name;
public function exchangeArray($data)
{
$this->collectionID = (!empty($data['collectionID'])) ? $data['collectionID'] : null;
$this->name = (!empty($data['name'])) ? $data['name'] : null;
}
// Add the following method:
public function getArrayCopy()
{
return get_object_vars($this);
}
}
If I add my own
public function toArray()
{
return array(get_object_vars($this));
}
I can coerce it into doing what I'd expect, but I'm not sure this is the best approach. Also if I use that in conjunction with JsonModel the JSON outputted will also contain variables from settings.global.php
Thanks in advance,
You have to loop through the records, as it won't fetch all in one go. So something like:
$m = array();
foreach($resultSet as $r)
$m[] = (array)$r;
Or else try:
$resultSet = (array)resultSet;
You should be able to use, $result->getArrayCopy()
if it doesn't work you could try adding to Collection this function
public function getArrayCopy()
{
return get_object_vars($this);
}

PHP object method doesn't behave as I expect

I can't quite understand why the output of this code is '1'.
My guess is that php is not behaving like most other OO languages that I'm used to, in that the arrays that php uses must not be objects. Changing the array that is returned by the class does not change the array within the class. How would I get the class to return an array which I can edit (and has the same address as the one within the class)?
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function getArr()
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = $t->getArr();
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
EDIT: I expected the output to be 0
You have to return the array by reference. That way, php returns a reference to the array, in stead of a copy.
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function & getArr() //Returning by reference here
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = &$t->getArr(); //Reference binding here
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
This returns 0.
From the returning references subpage:
Unlike parameter passing, here you have to use & in both places - to
indicate that you want to return by reference, not a copy, and to
indicate that reference binding, rather than usual assignment, should
be done
Note that although this gets the job done, question is if it is a good practice. By changing class members outside of the class itself, it can become very difficult to track the application.
Because array are passed by "copy on write" by default, getArr() should return by reference:
public function &getArr()
{
return $this->arr;
}
[snip]
$tobj_arr = &$t->getArr();
For arrays that are object, use ArrayObject. Extending ArrayObject is probably better in your case.
When you unset($tobj_arr[0]); you are passing the return value of the function call, and not the actual property of the object.
When you call the function again, you get a fresh copy of the object's property which has yet to be modified since you added 5 to it.
Since the property itself is public, try changing:
unset($tobj_arr[0]);
To: unset($t->arr[0]);
And see if that gives you the result you are looking for.
You are getting "1" because you are asking PHP how many elements are in the array by using count. Remove count and use print_r($tobj_arr_fresh)

Categories