I'm working with a third-party class, and I need to be able to run a section of code one of two ways, depending...
$reader->get()->first()->each(function($obj)
{
// Do stuff
}
OR
$reader->get()->each(function($obj)
{
// Do stuff
}
I've always been able to call properties variably with something like...
$a = 1;
$obj->{"$a"}
But unfortunately the below doesn't work...
if (some scenario)
{
$a = "get()->first()";
}
else
{
$a = "get()";
}
$reader->{"$a"}->each(function($obj)
My problem is i'm not sure how to phrase the question for google...I'm assuming there's a solution for the above problem.
Thanks in advance for any help!
You can only use ->{$variable} for the names of properties and methods of the class itself, you can't put PHP syntax like -> in there. What you can do is use function variables:
function get_all($reader) {
return $reader->get();
}
function get_first($reader) {
return $reader->get()->first();
}
$a = 'get_all'; // or $a = 'get_first';
$a($reader)->each(function($obj) {
// do stuff
});
Alternative to Barmar's answer, which imho is a bit clearer.
$it = function($obj) {
// do stuff
});
if (some_scenario) {
$reader->get()->first()->each($it);
} else {
$reader->get()->each($it);
}
One more solution:
if (some_scenario) {
$foo = $reader->get()->first();
} else {
$foo = $reader->get();
}
$foo->each(function($obj) {
// do stuff
});
Related
im just learning php
Im trying to add a log with comments to my functions output.
Right now it looks like this:
//the function
function add1($x){
if($GLOBALS['logging'] === 'on'){ $log[] = 'Adding 1 to '.$x;};
$a = $x + 1;
if($GLOBALS['logging'] === 'on'){
$return[] = $a;
$return[] = $log;
return $return;
}else{ return $a; };
};
//calling the function
if($GLOBALS['logging'] === 'on'){
$return = add1($x);
$number = $return[0];
$log = $return[1];
}else{ $number = add1($x); };
Im kinda annoyed by the fact i need to retype this if statement.
So i made a seperate function for returning the function
which looks like this:
//function
function log_return($data = 'x', $log = 'x'){
if($GLOBALS['logging'] === 'on'){
if($data !== 'x') $return[] = $data;
if($log !== 'x') $return[] = $log;
return $return;
} return $data;
};//function end
And returning it with:
return $return = isset($log) ? log_return($data, $log) : log_return($data);
Now my quastion is: Is there a way to call a function with function..
like:
call_function(add1($x));
so i can return it either with log or without..
Given the answer https://stackoverflow.com/a/2700760/5387193 - this should work:
function add1($a)
{
// add1 code goes here
}
function call_function($name, $param)
{
$name($param);
}
call_function('add1', $x);
On a side note, your variable and function names aren't very intuitive. Perhaps you should study how to write good quality readable code. I recommend reading chapter 9 of Refactoring by Martin Fowler, it's quite good. You can find a PDF version on the web.
Another note, your return statement return $return = isset($log) ? log_return($data, $log) : log_return($data); has a unnecessary assignment to $return. The code should simply read
return isset($log) ? log_return($data, $log) : log_return($data);
Yes, it is possible. To simplify:
function first($x) {
return $x+1;
}
function second($y) {
return $y+1;
}
echo second(first(1)); // Returns 3, ie. 1+1+1
As gview said in his comment, don't use global variables. Argument lists exist for several reasons, included but not limited to making code easier to read, edit, and debug. The same goes for function and variable names.
Moreover, your code is very messy. It can be consolidated:
function addTo($currentValue, $valueToAdd, $logging = 0)
{
if ($logging) {
logWrite('addTo', "Adding $valueToAdd to $currentValue");
return $currentValue + $valueToAdd;
} else {
return $currentValue;
}
}
function logWrite($operation, $message)
{
$log = getLog(); // maybe it's a file, or DB record or something
// perform the write, depending on your implementation
}
$number = addTo($someStaringValue, $someOtherValue, 1);
All of this said, logging should not control program flow. In other words, whether something is logged by the system or not should have no bearing on what your code is trying to do. I really think you need to take a broader view of what you're trying to do and break it up into components.
At best, your code should tell a logger to log info, and the logger itself should determine if logging is actually turned on. If it is, the info is logged. If not, then the code that calls on the logger still works and goes about its business.
Here is the code :
<?php
$a_campagnes = $this->campagne->get_campagnes_client();
foreach($a_campagnes as $o_camp){
if($o_camp->groupes){
foreach($o_camp->groupes as $o_groupe){
if($o_groupe->IDGroupe == $this->session->o_user->IDGroupe){ echo 'ok';}
}
}
}
$a_campagnes = array_filter($a_campagnes, function($o_camp){
if($o_camp->groupes){
foreach($o_camp->groupes as $o_groupe){
if($o_groupe->IDGroupe == $this->session->o_user->IDGroupe) return true;
}
}
return false;
});
$a_campagnes contains at first 10 objects
The result of the first foreach is okokokok
The result of $a_campagnes after the array_filter (which is the same code as the first foreach) is null
Where are the four objects matching my first foreach?
EDIT
Just tried that piece of code:
$i_id_groupe_user = $this->session->o_user->IDGroupe;
foreach($a_campagnes as $o_camp){
if($o_camp->groupes){
foreach($o_camp->groupes as $o_groupe){
if($o_groupe->IDGroupe == $i_id_groupe_user){ echo 'ok';}
}
}
}
$a_campagnes = array_filter($a_campagnes, function($o_camp) use ($i_id_groupe_user){
if($o_camp->groupes){
foreach($o_camp->groupes as $o_groupe){
if($o_groupe->IDGroupe == $i_id_groupe_user) return true;
}
}
return false;
});
It gives the same result as before
$this doesn't exist inside anonymous functions, and you're trying to use it as if it was inside your class scope, which would be even less logical.
If you want to use whatever $this->session is inside your array_filter() callback, you'll have to either declare a class method specifically for that, or tell the anonymous function that it can use it, like this:
$session = $this->session;
$a_campagnes = array_filter($a_campagnes, function($o_camp) use ($session) {
if ($o_camp->groupes) {
foreach($o_camp->groupes as $o_groupe) {
if ($o_groupe->IDGroupe == $session->o_user->IDGroupe) return true;
}
}
return false;
});
Toplevel equivalent in PHP of "return" keyword outside function blocks ?
A nice, useful property of the return keyword is that when it is invoked,
it exits the main function block in which it is, no matter how many other
nested blocks may surround it.
I am not aware of any equivalent for the toplevel scope. And I would like
to have a systematic way of "expanding" a function
call into an equivalent list of statements, and for that I need to know
a systematic way to deal with all the return ’s in the code.
Consider for example
function seekAUnicorn()
{
for($i=1;some_test($i);$i++) {
for($j=1;some_test($j);$j++) {
for($k=1;some_test($k);$k++) {
if(unicorn_test_for_three_parameters($i,$j,$k)) return(array($i,$j,$k));
}
if(unicorn_test_for_two_parameters($i,$j)) return(array($i,$j));
}
if(unicorn_test_for_one_parameter($i)) return(array($i));
}
}
The expansion of $searchResult=seekAUnicorn(); might look something like this :
for($i=1;some_test($i);$i++) {
for($j=1;some_test($j);$j++) {
for($k=1;some_test($k);$k++) {
if(unicorn_test_for_three_parameters($i,$j,$k)) {
$searchResult = array($i,$j,$k);
break 3;
}
}
if(unicorn_test_for_two_parameters($i,$j)) {
$searchResult = array($i,$j);
break 2;
}
}
if(unicorn_test_for_one_parameter($i)){
$searchResult = array($i);
break;
}
}
But to do it this way, you need to count the number of nested blocks
around each nested return, which becomes painstaking and error-prone for
longer and more complicated code. Is there a simpler way ?
In your case, you can either use goto (since PHP 5.3) or by adding another simple check.
$loopcheck = true;
for($i=1;some_test($i) && $loopcheck;$i++) {
for($j=1;some_test($j) && $loopcheck;$j++) {
for($k=1;some_test($k) && $loopcheck;$k++) {
if(unicorn_test_for_three_parameters($i,$j,$k)) {
$searchResult = array($i,$j,$k);
$loopcheck = false;
break;
}
}
if(unicorn_test_for_two_parameters($i,$j)) {
$searchResult = array($i,$j);
$loopcheck = false;
break;
}
}
if(unicorn_test_for_one_parameter($i)){
$searchResult = array($i);
$loopcheck = false;
}
}
To unset a variable without cheking whether it has been already used or declared.Which is valid in PHP: (a) or (b)? Although both works. In the sample code below,forward referencing is used,how PHP handles it internally?
(a)
while(stmt1->fetch())
{
unset($data);
$i=0;
while(stmt2->fetch())
{
//Some code.......
$data[$i] = $some_Value;
$i++;
}
}
(b)
while(stmt1->fetch())
{
if(isset($data))
{
unset($data);
}
$i=0;
while(stmt2->fetch())
{
//Some code.......
$data[$i] = $some_Value;
$i++;
}
}
Instead of unsetting the variable, set it with an initial value. This conveys the intention much clearer.
Also, you don't need to keep track of $i to insert a new element:
while ($stmt1->fetch()) {
$data = []; //Initialize empty array. This is PHP 5.4+ syntax.
while ($stmt2->fetch()) {
$data[] = $someValue; //$array[] means "Push new element to this array"
}
}
Method B is not neccessary. If you unset a non-existing variable nothing will happen, you won't get an undefined variable error.
You can see this behaviour here (it has error_reporting(E_ALL)).
Just in case you see it is some other code, I've already seen something like the following code (It's not the real code, only to give an idea of the use case).
The isset what used like "isset and with validated value". I'm not saying it's good practice (of course it's not, and even worse in this simplified example), it's just to show that, with overloaded magic methods, it may have some sense.
class unsetExample {
private $data = 'some_value';
public function __isset($name) {
if ($this->${name} != 'my_set_value') {
return false;
} else {
return true;
}
public function __unset($name) {
unset($this->${name});
echo 'Value unset';
}
}
$u = new unsetExample;
if (isset($u->data)) {
unset($u->data);
} else {
echo 'In that case I don\'t want to unset, but I will do something else instead';
}
Edit : Changed the code, it's much more how it was is the real code now
If certain elements are contained in an array, I want them moved to the start of it.
At first I used a bunch of array_diff_keys to get it to work, but I wanted something more elegant. So I tried using uksort with a callback, but perhaps I'm doing it wrong because it's not working.
I tried this, it's a method of my helper class, but it's not working.
$good_elements = array('sku','name','type','category','larping');
$test_array = array('sku','name','asdf','bad_stuff','larping','kwoto');
$results = helper::arrayPromoteElementsIfExist($test_array,$good_elements,false);
public static function arrayPromoteElementsIfExist($test_array,$promote_elements,$use_keys = false) {
foreach(array('test_array','promote_elements') as $arg) {
if(!is_array($$arg)) {
debug::add('errors',__FILE__,__LINE__,__METHOD__,'Must be array names',$$arg);
return false;
}
}
if(!$use_keys) {
$test_array = array_flip($test_array); // compare keys
$promote_elements = array_flip($promote_elements); // compare keys
}
uksort($test_array,function($a,$b) use($promote_elements) {
$value1 = intval(in_array($a, $promote_elements));
$value2 = intval(in_array($b,$promote_elements));
return $value1 - $value2;
});
if(!$use_keys) {
$test_array = array_flip($test_array);
}
return $test_array;
}
Fairly quick and dirty but here you go.
function promoteMembers($input, $membersToPromote)
{
$diff = array_diff($input, $membersToPromote);
return array_merge($membersToPromote, $diff);
}
Assuming I understood what you wanted to do.
Example output: for your verification.