I have two classes. In my parent class I have this function:
protected function assign($items, $array)
{
foreach($items as $item)
{
$array[$item] = $item;
}
return $array;
}
I use the second array parameter to determine which array to append to.
Then I call it from my child class like this.
$this -> assign($this -> attributes, $this -> values);
That doesn't work but if I hardcode the name of the array in the parent class to $this -> values then it works as it should. I want to know what I am doing wrong and how to do it correctly.
Thanks
Try the below code
protected function assign($items, &$array)
{
foreach($items as $item)
{
$array[$item] = $item;
}
return $array;
}
Related
I have an object with 2 attributes: id and name (class name: MyObject):
class MyObject {
public id;
public name;
}
And I have an array "MyObjects" where each item is a MyObject instance.
I am looping through this array to display all the objects in one view (MVC Web Application).
In an other place (Outside of the view and the controller (Validation class)) I will need an array of just the ids of all objects. What I am doing now is just use a private method in the controller to loop through "MyObjects" again and put the ids in an array:
private function getMyObjectsIds($myObjects) {
$myObjectsIds = array();
foreach ($myObjects as $myObject) {
$myObjectsIds[] = $myObject->id;
}
return $myObjectsIds;
}
My Question:
Is there a better way to retrieve the ids of all the objects as an array?
I do not feel like this is the job of the controller and I would prefer to not save MyObjects in a new attribute of the model to just use the same method from the model.
Thanks
I would use array_map for it:
$myObjectsIds = array_map(function($item) {
return $item->id;
}, $myObjects);
http://php.net/manual/en/function.array-map.php
You can create your own "array" class where that logic is encapsulated.
For example:
class Collection
{
public $items;
public function __construct(array $items)
{
$this->items = $items;
}
public function lists($name)
{
return array_map(function ($item) use ($name) {
return $item->{$name};
}, $this->items);
}
// Other common methods
}
To get a list of ids.
$myObjects = new Collection([]);
$ids = $myObjects->lists('id');
This is not a full example, as you would also need to implement Serializable and Iterator interfaces so it behaves like an array.
<?php
$arr=array("b"=>4,"a"=>2,"c"=>8,"d"=>"6");
class Sort {
public $arr = array();
public function __construct(&$arr=array()) {
$this->arr = $arr;
}
static function my_sort($a,$b) {
//I am trying to cycle through the array $arr within this class
foreach ($this->arr as $key => $value) {
print "success";
}
if ($a==$b)
return 0;
return ($a<$b)?-1:1;
}
}
uasort($arr,array("Sort","my_sort"));
print_r($arr);
?>
I would like to cycle through the array $arr using foreach, while also within the sorting function my_sort, but I can't figure out how to properly reference the array. I set up a public constructor which references the array, but I'm unsure of how to interact with the array after it's been initialized.
imo there is 2 problems :
"importing" the array into you class: what you did is ok
$arr = array("b"=>4,"a"=>2,"c"=>8,"d"=>"6");
$sort = new Sort($arr);
Your array is now referenced in you class
sorting you array: add a sort() function to your class
public function sort()
{
return uasort($this->arr, array(__CLASS__, "my_sort"));
}
Use the function
$sort->sort();
PS: your my_sort function is wrong, it should not contain $this. Use another non static function to walk throw the array.
You can modify the sort() function ie:
public function sort()
{
foreach ($this->arr as $item) {
//stuff
}
return uasort($this->arr, array(__CLASS__, "my_sort"));
}
I have an object that implements Iterator and holds 2 arrays: "entries" and "pages". Whenever I loop through this object, I want to modify the entries array but I get the error An iterator cannot be used with foreach by reference which I see started in PHP 5.2.
My question is, how can I use the Iterator class to change the value of the looped object while using foreach on it?
My code:
//$flavors = instance of this class:
class PaginatedResultSet implements \Iterator {
private $position = 0;
public $entries = array();
public $pages = array();
//...Iterator methods...
}
//looping
//throws error here
foreach ($flavors as &$flavor) {
$flavor = $flavor->stdClassForApi();
}
The reason for this is that sometimes $flavors will not be an instance of my class and instead will just be a simple array. I want to be able to modify this array easily regardless of the type it is.
I just tried creating an iterator which used:
public function ¤t() {
$element = &$this->array[$this->position];
return $element;
}
But that still did not work.
The best I can recommend is that you implement \ArrayAccess, which will allow you to do this:
foreach ($flavors as $key => $flavor) {
$flavors[$key] = $flavor->stdClassForApi();
}
Using generators:
Updating based on Marks comment on generators, the following will allow you to iterate over the results without needing to implement \Iterator or \ArrayAccess.
class PaginatedResultSet {
public $entries = array();
public function &iterate()
{
foreach ($this->entries as &$v) {
yield $v;
}
}
}
$flavors = new PaginatedResultSet(/* args */);
foreach ($flavors->iterate() as &$flavor) {
$flavor = $flavor->stdClassForApi();
}
This is a feature available in PHP 5.5.
Expanding upon Flosculus' solution, if you don't want to reference the key each time you use the iterated variable, you can assign a reference to it to a new variable in the first line of your foreach.
foreach ($flavors as $key => $f) {
$flavor = &$flavors[$key];
$flavor = $flavor->stdClassForApi();
}
This is functionally identical to using the key on the base object, but helps keep code tidy, and variable names short... If you're into that kind of thing.
If you implemented the iterator functions in your calss, I would suggest to add another method to the class "setCurrent()":
//$flavors = instance of this class:
class PaginatedResultSet implements \Iterator {
private $position = 0;
public $entries = array();
public $pages = array();
/* --- Iterator methods block --- */
private $current;
public function setCurrent($value){
$this->current = $value;
}
public function current(){
return $this->current;
}
//...Other Iterator methods...
}
Then you can just use this function inside the foreach loop:
foreach ($flavors as $flavor) {
$newFlavor = makeNewFlavorFromOldOne($flavor)
$flavors -> setCurrent($newFlavor);
}
If you need this function in other classes, you can also define a new iterator and extend the Iterator interface to contain setCurrent()
I am looking for a way to intercept the action in array_push, because when it will be retrieve it each value of the array has another info like:
class ClassName {
var $test = array();
function __set($attr, $value) {
$this->$attr = 'My extra value'.$value;
}
function index(){
array_push($this->test, "some val");
array_push($this->test, "some other val");
print_r($this->test);
}
}
$o = new ClassName();
$o->index();
And expected to get something like:
Array
(
[0] => My extra value some val
[1] => My extra value some other val
)
But i get:
Array
(
[0] => some val
[1] => some other val
)
Thanks to all
Instead of using an array, you can use a class that implements the ArrayAccess interface. This way you have full control over what occurs when you append to the array.
http://php.net/manual/en/class.arrayaccess.php
The drawback is that not all array functions will work on the object (ie sorting etc), but you can push like so:
$object[] = 'new value';
The alternative is to simply make a wrapper function for adding to the array.
public function addToArray($key, $value) {
if ($key === null) {
$this->test[] = 'My extra value ' . $value;
} else {
$this->test[$key] = 'My extra value ' . $value;
}
}
I don't totally understand what you're asking, but are you trying to do this:
$this->test['key'] = "some val";
That will allow you to setup your own output nicely. Because array_push() will throw on another nested level.
Update: Maybe something along these lines?
function push($prefix)
{
$refl = new ReflectionClass($this);
$prop = $refl->getProperties();
foreach($prop as $p) {
$this->{$p} = $prefix . $this->{$p};
}
}
To achieve what you're looking for, I suggest you create yourself a function that prefixes any value independent to it's use:
function prefix($value) {
return 'My extra value '.$value;
}
You can then make use of that function inside the index() function:
function index()
{
$test = array("some val", "some other val");
foreach($test as $value)
{
$this->test[] = $this->prefix($value);
}
print_r($this->test);
}
From the PHP manual:
__set() is run when writing data to inaccessible properties.
__get() is utilized for reading data from inaccessible properties.
This is only called on reading/writing inaccessible properties. Your property however is public, which means it is accessible. Changing the access modifier to protected solves the issue.
Try this:
class ClassName {
private $test = array();
public function __set($attr, $value) {
$this->test[$attr] = $value;
}
public function __get($attr) {
return $this->test[$attr];
}
public function index(){
array_push($this->test, "some val");
array_push($this->test, "some other val");
return $this->test;
}
}
$o = new ClassName();
$o->setData = 'My extra value';
print_r($o->index());
The PHP manual says the following about magic methods:
__set() is run when writing data to inaccessible properties. (Emphasis mine)
Because the test property is inside the method and the function that is accessing it is inside the method, the function will see the variable directly and will not use the magic setter.
Additionally, even if you try to use array_push on the magic setter outside the class itself, that still will not work. You will get the error array_push() expects parameter 1 to be array, object given.
If you want to support array_push, you should write your own push($item) method:
function push($item) {
$this->test[] = 'My extra value' . $item
}
or:
function push() {
$items = func_get_args();
// Using array_map is one of the many ways to do this.
// You could also do it with a simpler `foreach` but I like this way.
$prepend = function($item) {
return 'My extra value' . $item;
};
$items = array_map($prepend, $items);
array_push($this->test, $items);
}
if you want to support pushing multiple items at once.
I have a class with 2 functions. One function has the array map that pass the array to another function within the same class. Unfortunatly the array is dumped as NULL. Any fix?
class filter
{
public function filt($value)
{
$value = mysql_escape_string($value);
$value = trim($value);
return $value;
}
public function passover($variables)
{
$variables = array_map("filt",$variables);
return $variables;
}
}
$filter = new filter();
$m= $filter->passover($arr =array('smith'=>1, 'smith'=>2));
var_dump($m);
To provide an object method as callback, you need a different syntax:
array_map(array($this, 'filt'), $variables)
http://php.net/manual/en/language.types.callable.php