I want to make a foreach loop like this one
foreach ($this->data['array'] as $this->data['key'] => $this->data['value'])
{
echo $this->data['value'];
}
Yet the $this->data['value'] is never created. Why is this and what am I doing wrong?
In my understanding, you have a class in which there is a variable or array name $data.
Now, you added an array in $data with an index named 'array', right?
If so, this code will work properly -
class myClass{
public $data = array(); //$data is an array
function print_array(){
foreach ($this->data['array'] as $this->data['key'] => $this->data['value'])
{
echo $this->data['value'];
}
}
}
$ob = new myClass(); // object declaration for your class
array_push($ob->data,'array'); // added a value to the $data array.
$ob->data['array'] = array(); // the newly added value is declared as an index of an array
// Now simply push values to the array named $data['array']
array_push($ob->data['array'],1);
array_push($ob->data['array'],2);
array_push($ob->data['array'],3);
$ob->print_array(); // call the print_array() function. $this will be passed to that function
Hope this will help to understand.
If you still have problem, please comment.
To have a clear understanding, you can visit this link. There are lots of simple and interesting examples explained!
Happy Coding!
I think $this is for current class object reference not for an array
foreach ($this->data['array'] as $k => $v)
{
echo $v;
$this->data['key'][] = $k;
$this->data['value'][] = $v;
}
print_r($this->data['key']);
print_r($this->data['value']);
If:
class YourClass {
private data = array(
'array' => array(
'key1' => 'val1',
'key2' => 'val2', etc.
)
);
then it should be:
foreach ($this->data['array'] as $key => $val)
{
echo $val;
// if you want to add keys and vals to data array:
$this->data[$key] = $val;
}
Related
I'm trying to add random numbers with array_push to an array in the field 'notes' => [] but I think I'm not doing it right since I do not see the random numbers stored in the array.
I am doing it in the following way:
$person1= [
'name' => 'person1',
'note' => []
];
$person2= [
'name' => 'person2',
'note' => []
];
$person3= [
'name' => 'person3',
'note' => []
];
$data=[$person1, $person2, $person3];
$_SESSION['data'] = $data;
function insertNumRandom(){
$data = $_SESSION['data'];
foreach ( $data as $student ) {
array_push($student['note'], rand(0,10));
}
}
function showNotes(){
foreach ( $data as $student ) {
echo implode($student['note']);
}
}
showNotes(); // To show the notes but it shows nothing.
You should change insertNumRandom like as below
function insertNumRandom(){
$data = $_SESSION['data'];
foreach ( $data as &$student ) {
array_push($student['note'], rand(0,10));
}
$_SESSION['data'] = $data;
}
showNotes function
function showNotes(){
$data = $_SESSION['data'];
foreach ( $data as $student ) {
echo implode($student['note']);
}
}
and call insertNumRandom before showNotes.
insertNumRandom();
showNotes();
You're referencing the $data with the "as" keyword which creates a new object.
You should instead iterate through the object you already have.
function insertNumRandom(){
$index = 0;
for($index = 0; $index<sizeof($data['data']); $index++ ) {
array_push($data[$index]['note'], rand(0,10));
}
}
try this maybe, still not sure how you're calling the insertNumRandom() function
function showNotes($arr){
foreach ( $arr as $student ) {
var_dump(implode($student['note']));
}
}
insertNumRandom();
showNotes($data);
you have a number of issues in your example.
First of all, the way you are using the $_SESSION object to pass some values to the function is not necessary, and not clean. You can either use global $data inside of the functions and they will suddenly have access to the $data variable from the parent scope. But even that is not very clean. I would suggest that you pass the data object by reference to the functions. That will make your function more portable and testable.
Your example is accessing the $student variable by value. All you need to do is to access it by reference by using the ampersand (&) in the foreach() like this foreach ( $data as &$student ) { ... }
I have noticed that you have never made a single call to insertNumRandom()
To have a better idea about what's in the arrays, I would suggest that you use a field separator for the implode() function and that you print a new line after imploding the array. I bet you will like the result.
Finally, just a word of advice ... array_push() lets you push one or more items in an array. But I personally use it only when I need to push multiple items in an array. For push just item new items, I use the short-hand $myArray[] = "new item";
So in practice, here is what your example will become ...
<?php
// Since you are not reusing $person1, $person2 and $person3 beyond the initialization
// phase, then let's keep things cleaner.
$data[] = [
'name' => 'person1',
'note' => []
];
$data[] = [
'name' => 'person2',
'note' => []
];
$data[] = [
'name' => 'person3',
'note' => []
];
/**
* In this function signature, the & means that the argument is passed by reference.
* That make it possible for the function to change the value of the argument.
*/
function insertNumRandom(&$theData) {
// The foreach() also needs to use $student by reference so that we can modify it
// by adding the random number to it.
foreach($theData as &$student) {
$student['note'][] = rand(0,10);
}
}
/**
* No need to pass $theData by reference because the function will not change its value.
*/
function showNotes($theData) {
// Here, the foreach() is using student by value because we do not need to change it's value.
foreach($theData as $student) {
echo implode($student['note'], ', ') . "\n";
}
}
// Inserting some random notes 3 times.
insertNumRandom($data);
insertNumRandom($data);
insertNumRandom($data);
showNotes($data); // To show the notes but it shows nothing.
?>
Is it possible to create multidimensional array with its keys defined in array? Yes, it is, according to bunch of Stack Overflow answers. Here is one: Dynamic array keys
function insert_using_keys($arr, array $path, $value) { // See linked answer }
$arr = create_multi_array($arr, array('a', 'b', 'c'), 'yay'));
print_r($arr);
Prints
Array ( [a] => Array ( [b] => Array ( [c] => yay ) ) )
Would the same be possible for class properties?
This is a barebone version of my Collection class. Method set_at should add a multidimensional array to $data property the same way insert_using_keys function does.
class A {
protected $data = array();
public function set($key, $value) {
$this->data[$key] = $value;
}
public function set_at(array $keys, $value) {
}
}
I've tried a several modifications of the insert_using_keys to no avail. I was able to set the keys to the property, but not assign value "to the last one".
Would someone point me in the right direction please? Thanks in advance!
In the midst of recreating the "key-setter" function, I was able to answer my own question (was it your intention all along, Stefan?).
Here is the code:
public function set_at(array $keys, $value) {
$first_key = array_shift($keys);
foreach (array_reverse($keys) as $key) {
$value = array($key => $value);
}
$this->data[$first_key] = $value;
}
Is it possible to set multiple properties at a time for an object in php?
Instead of doing:
$object->prop1 = $something;
$object->prop2 = $otherthing;
$object->prop3 = $morethings;
do something like:
$object = (object) array(
'prop1' => $something,
'prop2' => $otherthing,
'prop3' => $morethings
);
but without overwriting the object.
Not like the way you want. but this can be done by using a loop.
$map = array(
'prop1' => $something,
'prop2' => $otherthing,
'prop3' => $morethings
);
foreach($map as $k => $v)
$object->$k = $v;
See only 2 extra lines.
You should look at Object Oriented PHP Best Practices :
"since the setter functions return $this you can chain them like so:"
$object->setName('Bob')
->setHairColor('green')
->setAddress('someplace');
This incidentally is known as a fluent interface.
I would recommend you don't do it. Seriously, don't.
Your code is much MUCH cleaner the first way, it's clearer of your intentions, and you aren't obfocusing your code to the extent where sometime in the future someone would look at your code and think "What the hell was the idiot thinking"?
If you insist on doing something which is clearly the wrong way to go, you can always create an array, iterate it and set all the properties in a loop. I won't give you code though. It's evil.
You could write some setters for the object that return the object:
public function setSomething($something)
{
$this->something = $something;
return $this; //this will return the current object
}
You could then do:
$object->setSomething("something")
->setSomethingelse("somethingelse")
->setMoreThings("some more things");
You would need to write a setter for each property as a __set function is not capable of returning a value.
Alternatively, set a single function to accept an array of property => values and set everything?
public function setProperties($array)
{
foreach($array as $property => $value)
{
$this->{$property} = $value;
}
return $this;
}
and pass in the array:
$object->setProperties(array('something' => 'someText', 'somethingElse' => 'more text', 'moreThings'=>'a lot more text'));
I realise this is an old question but for the benefit of others that come across it, I solved this myself recently and wanted to share the result
<?php
//Just some setup
header('Content-Type: text/plain');
$account = (object) array(
'email' => 'foo',
'dob'=>((object)array(
'day'=>1,
'month'=>1,
'year'=>((object)array('century'=>1900,'decade'=>0))
))
);
var_dump($account);
echo "\n\n==============\n\n";
//The functions
function &getObjRef(&$obj,$prop) {
return $obj->{$prop};
}
function updateObjFromArray(&$obj,$array){
foreach ($array as $key=>$value) {
if(!is_array($value))
$obj->{$key} = $value;
else{
$ref = getObjRef($obj,$key);
updateObjFromArray($ref,$value);
}
}
}
//Test
updateObjFromArray($account,array(
'id' => '123',
'email' => 'user#domain.com',
'dob'=>array(
'day'=>19,
'month'=>11,
'year'=>array('century'=>1900,'decade'=>80)
)
));
var_dump($account);
Obviously there are no safeguards built in. The main caveat is that the updateObjFromArray function assumes that for any nested arrays within $array, the corresponding key in $obj already exists and is an object, this must be true or treating it like an object will throw an error.
Hope this helps! :)
I wouldn't actually do this....but for fun I would
$object = (object) ($props + (array) $object);
you end up with an stdClass composed of $objects public properties, so it loses its type.
Method objectThis() to transtypage class array properties or array to stdClass. Using direct transtypage (object) would remove numeric index, but using this method it will keep the numeric index.
public function objectThis($array = null) {
if (!$array) {
foreach ($this as $property_name => $property_values) {
if (is_array($property_values) && !empty($property_values)) {
$this->{$property_name} = $this->objectThis($property_values);
} else if (is_array($property_values) && empty($property_values)) {
$this->{$property_name} = new stdClass();
}
}
} else {
$object = new stdClass();
foreach ($array as $index => $values) {
if (is_array($values) && empty($values)) {
$object->{$index} = new stdClass();
} else if (is_array($values)) {
$object->{$index} = $this->objectThis($values);
} else if (is_object($values)) {
$object->{$index} = $this->objectThis($values);
} else {
$object->{$index} = $values;
}
}
return $object;
}
}
Background
Assume I have the following nested variable in PHP.
$data = Array(
Array('lname' => 'Simpson','fname' => 'Homer','age' => '35','motto' => '_blank_'),
Array('lname' => 'Simpson','fname' => 'Marge','age' => '34','motto' => '_blank_'),
Array('lname' => 'Flintstone','fname' => 'Fred','age' => '33','motto' => '_blank_'),
Array('lname' => 'Flintstone','fname' => 'Wilma','age' => '29','motto' => '_blank_')
);
Assume also the standard methods for accessing specific values:
print($data[0]['fname']); // Homer
print($data[1]['age']); // 34
Question
Is there an existing library or framework that would allow me to easily
acess specific values declaratively, without using foreach loops?
$test = $data->get_record_by_fname['Homer']
print $test['age'] //35
If you really wanted to overkill everything, you could try an approach using magical methods!
class Simpsons
{
protected $_data = array();
public function __construct(array $data)
{
$this->_data = array_map(function ($i) { return (object)$i; }, $data);
}
public function __call($method, $args)
{
if (count($args) == 0)
return NULL;
foreach ($this->_data as $row)
{
if (property_exists($row, $method) && $row->$method == $args[0])
{
return $row;
}
}
return NULL;
}
}
Usage:
$p = new Simpsons($data); // Stored in the format provided
var_dump($p->fname('Homer')); // Gets the record with fname = Homer
Is there a particular reason you don't want to use foreach loops? If it's merely for conciseness, you could just declare the function yourself, it's fairly trivial:
function get_record($set, $field, $value) {
foreach($set as $key => $val) {
if($val[$field] === $value) return $set[$key];
}
return NULL;
}
Then your example would become:
$test = get_record($data, 'fname', 'Homer');
print $test['age']; //35
class SomeClass{
// Stores the Array of Data
public $data;
// Sets up the object. Only accepts arrays
public function __construct(array $data)
{
$this->data = $data;
}
// Gets a record based on the key/value pair
public function getByKey($key, $value)
{
foreach($this->data as $array)
{
if(is_array($array)
{
if(array_key_exists($key, $array) && $array[$key] == $value)
{
return $array;
}
}
}
}
}
$array = array( 1 => array("Test" => "Hello"));
$obj = new SomeClass($array);
$record = $obj->getByKey('Test', 'Hello');
This lets you get a record based on what a key/value pair inside the array is. Note, the type hinting in the constructor is PHP 5.3(?)
BTW, No, there is no way to escape the foreach as even internal PHP functions (anything beginning with array_) uses a foreach or some other type of loop. However, if you encapsulate the loop into a class, you don't have to think about it.
I want to take an array and use that array's values to populate an object's properties using the array's keynames. Like so:
$a=array('property1' => 1, 'property2' => 2);
$o=new Obj();
$o->populate($a);
class Obj
{
function Populate($array)
{
//??
}
}
After this, I now have:
$o->property1==1
$o->property2==2
How would I go about doing this?
foreach ($a as $key => $value) {
$o->$key = $value;
}
However, the syntax you are using to declare your array is not valid. You need to do something like this:
$a = array('property1' => 1, 'property2' => 2);
If you don't care about the class of the object, you could just do this (giving you an instance of stdClass):
$o = (Object) $a;
Hm. What about having something like
class Obj
{
var properties = array();
function Populate($array)
{
this->properties = $array;
}
}
Then you can say:
$o->properties['property1'] == 1
...