variable references & in Laravel - php

In the following code, I noticed &$list is passed by reference in the loop, however $user and $request are passed by variables. Passing $list directly to the loop won't change $list outside the loop scope.
public function index(Request $request, User $user)
{
$list = collect();
$someRelations()->each(function ($val) use (&$list, $request, $user) {
// mutate $list
});
dd($list);
}
Why is this?

Actually its the core PHP functionality rather than Laravel itself, basically when you are passing variables without reference, it actually clone the variable with the same name but in different locations. So, if you make any changes to it, there will be no changes to the value of the variable outside the scope.
Without reference
$x = 10;
(function() use ($x){
$x = $x*$x;
var_dump($x); // 100
})();
var_dump($x); // 10
But, if you pass the value by reference, instead of creating a new variable, it provides the reference to the same original variable. So, any changes made inside the function will change the value of the variable outside scope as well.
Pass by reference
$y = 10;
(function() use (&$y){
$y = $y*$y;
var_dump($y); // 100
})();
var_dump($y); // 100
To know more about it you could visit, https://www.php.net/manual/en/language.references.pass.php

Related

Class-Wide accessible static array, trying to push to it, but keeps coming back empty

class UpcomingEvents {
//Variable I'm trying to make accessible and modify throughout the class methods
private static $postObjArr = array();
private static $postIdArr = array();
private static $pinnedPost;
//My attempt at a get method to solve this issue, it did not
private static function getPostObjArr() {
$postObjArr = static::$postObjArr;
return $postObjArr;
}
private static function sortByDateProp($a, $b) {
$Adate = strtotime(get_field('event_date',$a->ID));
$Bdate = strtotime(get_field('event_date',$b->ID));
if ($Adate == $Bdate) {
return 0;
}
return ($Adate < $Bdate) ? -1 : 1;
}
private static function queryDatesAndSort($args) {
$postQuery = new WP_Query( $args );
if( $postQuery->have_posts() ) {
while( $postQuery->have_posts() ) {
$postQuery->the_post();
//Trying to push to the array, to no avail
array_push(static::getPostObjArr(), get_post());
}
}
//Trying to return the array after pushing to it, comes back empty
return(var_dump(static::getPostObjArr()));
//Trying to sort it
usort(static::getPostObjArr(), array(self,'sortByDateProp'));
foreach (static::getPostObjArr() as $key => $value) {
array_push(static::$postIdArr, $value->ID);
}
}
}
I'm trying to access $postObjArr within the class, and push to it with the queryDatesAndSort(); method. I've tried a couple of things, most recent being to use a get method for the variable. I don't want to make it global as it's bad practice I've heard. I've also tried passing by reference I.E
&static::$postObjArr;
But when it hits the vardump, it spits out an empty array. What would be the solution and best practice here? To allow the class methods to access and modify a single static array variable.
static::$postObjArr[] = get_post()
I didn't think it would of made a difference, but it worked. Can you explain to me why that worked but array.push(); Did not?
Arrays are always copy-on-write in PHP. If you assign an array to another variable, pass it into a function, or return it from a function, it's for all intents and purposes a different, new array. Modifying it does not modify the "original" array. If you want to pass an array around and continue to modify the original array, you'll have to use pass-by-reference everywhere. Meaning you will have to add a & everywhere you assign it to a different variable, pass it into a function, or return it from a function. If you forget your & anywhere, the reference is broken.
Since that's rather annoying to work with, you rarely use references in PHP and you either modify your arrays directly (static::$postObjArr), or you use objects (stdClass or a custom class) instead which can be passed around without breaking reference.

Is it possible to Delete a value passed to a method, from within the method

Say I have a method (which in this particular case is a static method), and this method works on a given value. Once completed is there a way that I can automatically in the code, delete the variable (rather than the function copy).
I suspect from all I've read that this is not possible, but there are no clear declarations of such that my searching has found.
An example case:
Static Method:
public static function checkKey($keyValue = null)
{
if(!is_null($keyValue) && !empty($keyValue)) {
if($_SESSION['keyValue'] == $keyValue) {
unset($keyValue,$_SESSION['keyValue']);
return true;
}
unset($keyValue,$_SESSION['keyValue']);
return false;
}
return false;
}
Usage:
$valueToBeChecked = "I want this value unset from within the function"
//PHP page code
AbstractClass::checkKey($valueToBeChecked);
Is there a way that the method checkKey above can delete the value of $valueToBeChecked from within the method checkKey?
The fact it's a static method shouldn't be too critical, it's more the shape of is there a way that the function can delete a value that is set outside the funtion/method, when passed the variable as a parameter?
I realise this is possible if the whole thing is wrapped in a Class and the variable is saved as a class level variable (unset($this->var)), but I'm curious if there's any ability to "reach" variables from outside the scope such as
public static function checkKey($keyValue = null)
{
unset(\$keyValue);
}
I only have limited experience with namespacing but that's my best guess as to if this is possible, how to go about it.
simplified equiviliant outcome:
What I'm trying to reach is this action, entirely within the method:
$valueToBeChecked = "something"
AbstractClass::checkKey($valueToBeChecked);
unset($valueToBeChecked);
You cannot unset a variable from within a function and have that effect propagate. Per the manual:
If a variable that is PASSED BY REFERENCE is unset() inside of a function, only the local variable is destroyed. The variable in the calling environment will retain the same value as before unset() was called.
However, you can get equivalent behavior through pass-by-reference and setting to null:
function kill(&$value) {
$value = null;
}
var_dump($x); // NULL
$x = 'foo';
var_dump($x); // 'foo'
kill($x);
var_dump($x); // NULL
This works because, in PHP, there's no distinction made between a symbol that doesn't exist and a symbol that exists with a NULL value.

Using a function in php - what am I doing wrong?

$users = [
"Andrew",
"Max",
"Larry",
"Ricardo",
"Lucy",
"Marcus",
"Sophie"
];
$sector_rel = [];
$location_rel = [];
function sectorRel($user){
return sector_rel[] = round(1/rand(1,10),3);
}
function locationRel($user){
return $location_rel[] = round(1/rand(1,20),3);
}
foreach($users as $user){
sectorRel($user);
locationRel($user);
}
This:
function sectorRel($user){
return sector_rel[] = round(1/rand(1,10),3);
}
Should be/could be:
function sectorRel($user){
global sector_rel;
sector_rel[] = round(1/rand(1,10),3);
}
The problem is that the functions don't have access to the array variables. You can import them into the function scope using the keyword global, if they are indeed global variables. Now, having global variables isn't a good thing, and for a small test it's okay, but eventually you'll be eliminating your globals and this solution won't work.
But alternatively, you could pass the array variables to the function as an argument. However, this still introduces a lot of logic in the function. The function has to be told about the array, it must know that it needs to add a value to the end, and it also needs to calculate the actual value to add.
So better, make the function just return the calculated value and add it to the array outside of the function:
function sectorRel($user){
// Assuming your are going to use 'user' here somewhere?
return round(1/rand(1,10),3);
}
function locationRel($user){
return round(1/rand(1,20),3);
}
foreach($users as $user){
sector_rel[] = sectorRel($user);
$location_rel[] = locationRel($user);
}
You can then wrap this entire snippet of code into another function and call that to populate the arrays. That way, you've quite reasonably split the responsibilities of the functions and have a piece of code that looks nice and clean.
You do not need to use return in either of sectorRel or locationRel. At the moment this will return the reference to that array and it is not being stored in a variable. You would need to store them in a variable or just get rid of the return. My PHP is a little weak at the moment but you should probably append the values in those functions to the array.
Also if you have a parameter called $user for each of those functions you should either use that parameter or just get rid of it.

$provider = function() vs function provider()

I've seen in various coding examples different coding style when creating functions.
What is the difference between creating a function using
$provider = function() { code here }
vs
function provider(){ code here }
Is the first example simply a short version of: $data = provider(); ?
When do we use the first example?
No, it isn't. First code is declaration of closure, i.e. anonymous function. It has no name and can be called with identifier that holds it. Second sample is normal function (user-defined function, to be more specific) and, thus, it will be accessible within all scopes via it's name - not like closure, which will be available for calling only within scope, where it was defined.
You can have as many closures as you wish - they are just callable entities, for example this is valid:
$provider = function() { Code here }
$another = function() { Code here } //same code
-and calling $provider (for example, with call_user_func()) will have nothing to do with $another
Another significant difference is that closure can accept context parameters like:
$provider = function() use ($param1, $param2, ...) { Code here }
-so inside it's body context parameters will be available. Context parameters are not like usual arguments - since context parameters defined and exist independent from closure while arguments are evaluated at the moment, when call happened.
First declaration is anonymous function.And after assignment,we have variable with name $provider and can call $provider() .Second declaration its just normally function.
Anonymous function can be user for example in array_map,array_filter.For example
$a = array(1, 2, 3, 4, 5);
$res = array_filter(
$a, function ($elem) {
return $elem > 3;
}
);
print_r($res);
output element who larger 3

different explanation

The code
$global_obj = null;
class my_class
{
var $value;
function my_class()
{
global $global_obj;
$global_obj = &$this;
}
}
$a = new my_class;
$a->my_value = 5;
$global_obj->my_value = 10;
echo $a->my_value;
echoes 5, not 10.
"Upon first examination, it would seem that the constructor of my_class stores a reference to itself inside the $global_obj variable. Therefore, one would expect that, when we later change the value of $global_obj->my_value to 10, the corresponding value in $a would change as well. Unfortunately, the new operator does not return a reference, but a copy of the newly created object."
I still don't understand it, so can anyone please explain it differently, and help me understand?
Not sure why this is the way it works, but, if you remove the & in front of $this while assigning it to your global variable, it will work.
To illustrate that, the following portion of code :
$global_obj = null;
class my_class
{
public $my_value;
public function __construct()
{
global $global_obj;
$global_obj = $this;
}
}
$a = new my_class;
$a->my_value = 5;
$global_obj->my_value = 10;
echo $a->my_value;
Gives the following output :
10
Here are the differences with your code :
I remove the & before $this : with PHP 5, there is no need for that, when working with objects
I translated the code to real PHP 5 :
__construct for the constructor
use public/protected/private, and not var for properties
As a sidenote, the code you posted should have given you the following warning :
Strict standards: Creating default object from empty value
Notes :
I'm using PHP 5.3.2
E_ALL doesn't include E_STRICT (source)
EDIT after some more searching :
Going through the References Explained section of the PHP manual, and, more specifically the What References Do page, there is a warning given that says (quoting) :
If you assign a reference to a
variable declared global inside a
function, the reference will be
visible only inside the function. You
can avoid this by using the $GLOBALS
array.
And there is an example going with it.
Trying to use $GLOBALS in your code, I have this portion of code :
$global_obj = null;
class my_class
{
public $my_value;
public function __construct()
{
$GLOBALS['global_obj'] = & $this;
}
}
$a = new my_class;
$a->my_value = 5;
$global_obj->my_value = 10;
echo $a->my_value;
And I get the following output :
10
Which seems to work ;-)
If I replace the __construct method by this :
public function __construct()
{
global $global_obj;
$global_obj = & $this;
}
It doesn't work...
So it seems you should not use global, here, but $GLOBALS.
The explanation given in the manual is :
Think about global $var; as a
shortcut to $var =&
$GLOBALS['var'];. Thus assigning
another reference to $var only
changes the local variable's
reference.
And, just so it's said : using global variables is generally not quite a good idea -- and, in this specific situation, it feels like a very bad idea...
(Now, if this question what just to understand why... Well, I can understand your curiosity ;-) )

Categories