PHP foreach 循环 returns 额外不需要的数组(维基百科 API)
PHP foreach loop returns an extra unwanted array (Wikipedia API)
我整天都在研究这个问题,但没有找到任何解决方案。我也是 php.
的新手
我的函数的目的是获取维基百科文章的用户输入 (Category1) 及其类别 return。下面的基本函数可以毫无问题地执行此操作。
function get_all_categories ( ) {
$url = $this->get_url ( 'categories' ) ;
$url .= 'titles='.urlencode($_POST['Category1']);
$url .= '&cllimit=500' ;
$data = $this->get_result ( $url ) ;
$array = json_decode($data, true); }
城市规划的示例结果:
Array
(
[batchcomplete] =>
[query] => Array
(
[pages] => Array
(
[46212943] => Array
(
[pageid] => 46212943
[ns] => 0
[title] => Urban planning
[categories] => Array
(
[0] => Array
(
[ns] => 14
[title] => Category:All Wikipedia articles written in American English
)
[1] => Array
(
[ns] => 14
[title] => Category:Commons category with local link same as on Wikidata
)
[2] => Array
(
[ns] => 14
[title] => Category:Pages using ISBN magic links
)
[3] => Array
(
[ns] => 14
[title] => Category:Urban planning
)
[4] => Array
(
[ns] => 14
[title] => Category:Use American English from April 2015
)
[5] => Array
(
[ns] => 14
[title] => Category:Use dmy dates from April 2015
)
[6] => Array
(
[ns] => 14
[title] => Category:Wikipedia articles needing clarification from June 2015
)
[7] => Array
(
[ns] => 14
[title] => Category:Wikipedia articles with GND identifiers
)
)
)
)
)
)
当我尝试从该数组中仅提取标题值时,我的问题就开始了。我试图用 foreach 循环来做到这一点,这是我为多维数组找到的最简单的解决方案:
$array1 = new RecursiveIteratorIterator(
new RecursiveArrayIterator($array),
RecursiveIteratorIterator::SELF_FIRST);
foreach ($array1 as $key => $value) {
if (is_array($value) && $key == 'categories') {
$result = array_map(function($element){return $element['title'];}, $value);
print_r($result);
}
}
我用这段代码得到的是两个数组。一个只有标题的数组(我想要的),还有一个不需要的数组(有时包括第一个标题)附加到末尾:
Array
(
[0] => Category:All Wikipedia articles written in American English
[1] => Category:Commons category with local link same as on Wikidata
[2] => Category:Pages using ISBN magic links
[3] => Category:Urban planning
[4] => Category:Use American English from April 2015
[5] => Category:Use dmy dates from April 2015
[6] => Category:Wikipedia articles needing clarification from June 2015
[7] => Category:Wikipedia articles with GND identifiers
)
Array
(
[ns] =>
[title] => C
)
这个额外的数组是我不明白的。我认为问题是由 foreach 循环引起的。我尝试在循环外取消设置 $variable 但它没有帮助。如果我试图将这些结果传递给另一个函数,额外的数组会变得特别麻烦。我怎样才能防止这种情况发生?
为简单起见,您可以手动遍历数组而不是使用 RecursiveIteratorIterator
。
RecursiveIteratorIterator
将 kill performance 用于大型数组。
将您的提取逻辑更改为:
$result = array();
foreach($arr['batchcomplete']['query']['pages'] as $k => $v)
{
foreach($v['categories'] as $cat)
{
$result[] = $cat['title'];
}
}
正如@samir 提到的,手动执行会更快,但是如果您需要遍历未知深度的搜索机制,您也可以使用基本的递归函数。它可能比 OOP 风格快一点 RecursiveArrayIterator/RecursiveIteratorIterator:
function recurse($array,&$new)
{
foreach($array as $key => $value) {
if($key == 'title' && isset($array['ns'])) {
if(!isset($array['pageid']))
$new[] = $value;
}
else {
if(is_array($value)) {
recurse($value,$new);
}
}
}
}
# Set's storage array for final titles
$new = array();
# Recurse your array
recurse($array,$new);
# Show stored values
print_r($new);
这是 PHP 错误特征的有趣组合:
$key == 'categories'
是non-type-safe比较;数字数组键是整数,为了比较整数和字符串 PHP 将字符串转换为整数:粗略地说,它采用由数字组成的字符串的最长前缀。如果字符串根本不以数字开头,则字符串到整数转换的结果是 0
.
所以你的条件将两次为真:对于 categories
子数组及其第一个 child(带键 0
的那个)。提示:始终使用 ===
进行比较。
- PHP 允许在几乎所有非数组的对象上使用
[]
(数组索引)运算符(通常返回 null)。因此,当 array_map
尝试为 $element = 14
获取 $element['title']
(categories
子数组的第一个 child 的 ns
项)时,这将成功并导致 null(var_dump
仅显示为空)。
- 字符串略有不同:
'foo'[$n]
是获取字符串第 $n
个字符的有效旧语法。当数组索引运算符用于具有 non-integer 索引的字符串时,索引被转换为整数(正如我们所见,通常结果为零)。所以 'Category:...'['title']
将导致字符串 'C'
.
在对具有未知或不可靠结构的数组使用数组索引语法时,您应该始终不信任,并使用 isset
或其他东西类似于确保您尝试获取的数组字段存在。
我整天都在研究这个问题,但没有找到任何解决方案。我也是 php.
的新手我的函数的目的是获取维基百科文章的用户输入 (Category1) 及其类别 return。下面的基本函数可以毫无问题地执行此操作。
function get_all_categories ( ) {
$url = $this->get_url ( 'categories' ) ;
$url .= 'titles='.urlencode($_POST['Category1']);
$url .= '&cllimit=500' ;
$data = $this->get_result ( $url ) ;
$array = json_decode($data, true); }
城市规划的示例结果:
Array
(
[batchcomplete] =>
[query] => Array
(
[pages] => Array
(
[46212943] => Array
(
[pageid] => 46212943
[ns] => 0
[title] => Urban planning
[categories] => Array
(
[0] => Array
(
[ns] => 14
[title] => Category:All Wikipedia articles written in American English
)
[1] => Array
(
[ns] => 14
[title] => Category:Commons category with local link same as on Wikidata
)
[2] => Array
(
[ns] => 14
[title] => Category:Pages using ISBN magic links
)
[3] => Array
(
[ns] => 14
[title] => Category:Urban planning
)
[4] => Array
(
[ns] => 14
[title] => Category:Use American English from April 2015
)
[5] => Array
(
[ns] => 14
[title] => Category:Use dmy dates from April 2015
)
[6] => Array
(
[ns] => 14
[title] => Category:Wikipedia articles needing clarification from June 2015
)
[7] => Array
(
[ns] => 14
[title] => Category:Wikipedia articles with GND identifiers
)
)
)
)
)
)
当我尝试从该数组中仅提取标题值时,我的问题就开始了。我试图用 foreach 循环来做到这一点,这是我为多维数组找到的最简单的解决方案:
$array1 = new RecursiveIteratorIterator(
new RecursiveArrayIterator($array),
RecursiveIteratorIterator::SELF_FIRST);
foreach ($array1 as $key => $value) {
if (is_array($value) && $key == 'categories') {
$result = array_map(function($element){return $element['title'];}, $value);
print_r($result);
}
}
我用这段代码得到的是两个数组。一个只有标题的数组(我想要的),还有一个不需要的数组(有时包括第一个标题)附加到末尾:
Array
(
[0] => Category:All Wikipedia articles written in American English
[1] => Category:Commons category with local link same as on Wikidata
[2] => Category:Pages using ISBN magic links
[3] => Category:Urban planning
[4] => Category:Use American English from April 2015
[5] => Category:Use dmy dates from April 2015
[6] => Category:Wikipedia articles needing clarification from June 2015
[7] => Category:Wikipedia articles with GND identifiers
)
Array
(
[ns] =>
[title] => C
)
这个额外的数组是我不明白的。我认为问题是由 foreach 循环引起的。我尝试在循环外取消设置 $variable 但它没有帮助。如果我试图将这些结果传递给另一个函数,额外的数组会变得特别麻烦。我怎样才能防止这种情况发生?
为简单起见,您可以手动遍历数组而不是使用 RecursiveIteratorIterator
。
RecursiveIteratorIterator
将 kill performance 用于大型数组。
将您的提取逻辑更改为:
$result = array();
foreach($arr['batchcomplete']['query']['pages'] as $k => $v)
{
foreach($v['categories'] as $cat)
{
$result[] = $cat['title'];
}
}
正如@samir 提到的,手动执行会更快,但是如果您需要遍历未知深度的搜索机制,您也可以使用基本的递归函数。它可能比 OOP 风格快一点 RecursiveArrayIterator/RecursiveIteratorIterator:
function recurse($array,&$new)
{
foreach($array as $key => $value) {
if($key == 'title' && isset($array['ns'])) {
if(!isset($array['pageid']))
$new[] = $value;
}
else {
if(is_array($value)) {
recurse($value,$new);
}
}
}
}
# Set's storage array for final titles
$new = array();
# Recurse your array
recurse($array,$new);
# Show stored values
print_r($new);
这是 PHP 错误特征的有趣组合:
$key == 'categories'
是non-type-safe比较;数字数组键是整数,为了比较整数和字符串 PHP 将字符串转换为整数:粗略地说,它采用由数字组成的字符串的最长前缀。如果字符串根本不以数字开头,则字符串到整数转换的结果是0
.
所以你的条件将两次为真:对于categories
子数组及其第一个 child(带键0
的那个)。提示:始终使用===
进行比较。- PHP 允许在几乎所有非数组的对象上使用
[]
(数组索引)运算符(通常返回 null)。因此,当array_map
尝试为$element = 14
获取$element['title']
(categories
子数组的第一个 child 的ns
项)时,这将成功并导致 null(var_dump
仅显示为空)。 - 字符串略有不同:
'foo'[$n]
是获取字符串第$n
个字符的有效旧语法。当数组索引运算符用于具有 non-integer 索引的字符串时,索引被转换为整数(正如我们所见,通常结果为零)。所以'Category:...'['title']
将导致字符串'C'
.
在对具有未知或不可靠结构的数组使用数组索引语法时,您应该始终不信任,并使用isset
或其他东西类似于确保您尝试获取的数组字段存在。