The variable $id isn't in the scope of the function. You need to use the use clause to make external variables accessible:
$foo = array_filter($bar, function(
id) {
if (isset($obj->foo)) {
var_dump(
obj->foo == $id) return true;
}
return false;
});
See documentation for Anonymous functions (Example #3 "Inheriting variables from the parent scope").
Answer from Barmar on Stack OverflowThe variable $id isn't in the scope of the function. You need to use the use clause to make external variables accessible:
$foo = array_filter($bar, function(
id) {
if (isset($obj->foo)) {
var_dump(
obj->foo == $id) return true;
}
return false;
});
See documentation for Anonymous functions (Example #3 "Inheriting variables from the parent scope").
Variable scope issue!
Simple fix would be :
$id = '1';
var_dump(
foo = array_filter($bar, function($obj){
global $id;
if (isset($obj->foo)) {
var_dump(
obj->foo == $id) return true;
}
return false;
});
or, since PHP 5.3
$id = '1';
var_dump(
foo = array_filter($bar, function(
id) {
if (isset($obj->foo)) {
var_dump(
obj->foo == $id) return true;
}
return false;
});
Hope it helps
The scope of the variables inside an anonymous function is ONLY within the anonymous function.
You need to inherit the variable from the parent scope. You can find more details about it in the PHP Documentation about anonymous functions (Example #3)
which would transform this line:
$filtered = array_filter($json, function (
q) {
into this:
$filtered = array_filter($json, function (
q, $val) {
Add another variable in use:
$filtered = array_filter($json, function (
q, $key) {
if (stripos(
val], $q) !== false) {
return true;
} else {
return false;
}
});
EDIT:
One of good explanations can be found here: https://teamtreehouse.com/community/variable-functions-vs-php-closures
...the benefit of a lambda is that it exists only as long as the variable it is assigned to has a reference. So the way PHP manages memory is by reference counting. Essentially, the PHP engine reads all the files it needs in order to execute the program, and while doing so it finds all the variables used and keeps a tally of how many times they are used( reference count). While the script is being executed each time the variable is used it subtracts one from the reference count. Once the reference count hits zero, the variable is deleted (more or less). Normally, a function is loaded into memory and stays there for the entire execution of the script. However, a lambda can be deleted from memory once the reference count of its variable hits zero.
A closure on the other hand is an anonymous function that encapsulates a part of the global scope at the time it is created. In other words, you can pass a variable to a closure using the "use" keyword and that variable's value will be the same as it was when the closure was created regardless of what happen's outside the closure...
Basically use keyword is needed in order to created isolated scope for variables. Without it You wouldn't be able to inject any additional variable to the function.
Your $leagueKey variable is outside the scope of the anonymous function (closure). Luckily, PHP provides a very simple way to bring variables into scope - the use keyword. Try:
$leagueKey = 'NFL';
$response['response'] = array_filter($response['response'], function($tier) use ($leagueKey) {
return $tier['LeagueKey'] === $leagueKey;
});
This is just telling your anonymous function to "use" the $leagueKey variable from the current scope.
Edit
Exciting PHP 7.4 update - we can now use "short closures" to write functions that don't have their own scope. The example can now be written like this (in PHP 7.4):
$response['response'] = array_filter(
$response['response'],
fn($tier) => $tier['LeagueKey'] === $leagueKey
);
try this
$response['response'] = array_filter($response['response'], function($tier) use ($leagueKey) {
return ($tier['LeagueKey'] === $leagueKey ? true : false);
});
You have at least two options:
- Globalize the desired variable, and then reference it inside the callback
- Wrap the score calculation logic with a function, then reference it inside the callback
Globalize the Variable
<?php
global $score;
$score = 42; //Some crazy calculation I don't want to repeat.
function add_score_to_title($title) {
global $score;
return 'Quiz Results (' . $score . '/') - ' . $title;
}
add_filter( 'aioseop_title_single', 'add_score_to_title');
?>
Wrap the Score Calculation
If you only ever need the score calculation inside the filter, pull the logic into the callback itself:
<?php
function add_score_to_title($title) {
$score = 0;
$questions = get_quiz_result_questions();
$total_questions = 0;
foreach( $questions as $question ) {
$order = $question->order;
if( $order >= 100 ) {
break;
}
if( $question->correct == $_POST['Q'][$order] ) {
$score++;
}
$total_questions++;
return 'Quiz Results (' . $score . '/') - ' . $title;
}
add_filter( 'aioseop_title_single', 'add_score_to_title');
?>
Better yet, you could wrap your score calculation in a function of its own, and then call that function inside your callback:
<?php
function wpse48677_get_score() {
$score = 0;
$questions = get_quiz_result_questions();
$total_questions = 0;
foreach( $questions as $question ) {
$order = $question->order;
if( $order >= 100 ) {
break;
}
if( $question->correct == $_POST['Q'][$order] ) {
$score++;
}
$total_questions++;
$output['score'] = $score;
$output['total_questions'] = $total_questions;
return $output;
}
function add_score_to_title($title) {
$score_results = wpse48677_get_score();
$score = $score_results['score'];
return 'Quiz Results (' . $score . '/') - ' . $title;
}
add_filter( 'aioseop_title_single', 'add_score_to_title');
?>
If you find you have problems referencing the $_POST object, you can also register your query variable and then use get_query_var() internally to get data:
function add_score_query_vars( $query_vars ) {
$query_vars[] = 'Q';
return $query_vars;
}
add_filter( 'query_vars', 'add_score_query_vars' );
With this in place, $_POST['Q'] can be replaced with get_query_var('Q').
function add_score_to_title($title = false) {
static $score = false;
if($score === false){
// do calc
}
// plugin call (filter)
if($title !== false)
return 'Quiz Results (' . $score . ') - ' . $title;
// your call
return $score;
}
Call the function anywhere in your script to get the score, it will only be calculated once.
Another way, using anonymous functions:
// do the calc
$score = 'xxx';
add_filter('aioseop_title_single', function($title) use($score){
return 'Quiz Results (' . $score . ') - ' . $title;
});
if you are using php 5.3 and above, you can use closure to simplify your code:
Copy$NUM = 5;
$items = array(1, 4, 5, 8, 0, 6);
$filteredItems = array_filter($items, function($elem) use($NUM){
return $elem < $NUM;
});
As an alternative to @Charles's solution using closures, you can actually find an example in the comments on the documentation page. The idea is that you create an object with the desired state ($num) and the callback method (taking $i as an argument):
Copyclass LowerThanFilter {
private $num;
function __construct($num) {
$this->num = $num;
}
function isLower($i) {
return $i < $this->num;
}
}
Usage (demo):
Copy$arr = array(7, 8, 9, 10, 11, 12, 13);
$matches = array_filter($arr, array(new LowerThanFilter(12), 'isLower'));
print_r($matches);
As a sidenote, you can now replace LowerThanFilter with a more generic NumericComparisonFilter with methods like isLower, isGreater, isEqual etc. Just a thought — and a demo...