在PHP中循环获取数组的值

3

我有一个由以下内容组成的数组 $data:

$data[$k]['id'] = $row['iddevice'];
$data[$k]['temp_00'] = $row['temp_00'];
$data[$k]['temp_01'] = $row['temp_01'];
$data[$k]['temp_02'] = $row['temp_02'];
$data[$k]['temp_03'] = $row['temp_03'];
$data[$k]['temp_04'] = $row['temp_04'];

我这个数组中只有两个元素,所以echo count($data);会返回2

我正在使用 Morris.js 创建一个折线图,下面是一个可工作的代码示例:

$(function() {

    Morris.Line({
  element: 'morris-area-chart',
    data: [
  { y: '00h', 1:57, 2:41},
  { y: '01h', 1:62, 2:98},
  { y: '02h', 1:44, 2:43},
  { y: '03h', 1:67, 2:84},
  ],
  xkey: 'y',
  parseTime:false,
  ykeys: [1,2,3],
  pointSize: 2,
  hideHover: 'auto',
  labels: ['Capteur X', 'Capteur Y']
});

Morris.js 折线图

我的问题是,一旦我尝试使用PHP来使用从$data中获取的值,它就不起作用了,图表不会加载任何值。

   Morris.Line({
  element: 'morris-area-chart',
    data: [
    { y: '00h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_00'],2); $i++; }?>},
    { y: '01h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_01'],2); $i++; }?>},
    { y: '02h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_02'],2); $i++; }?>},
    { y: '03h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_03'],2); $i++; }?>},

  ],

对我来说,这个算法是可以的:

  • $i 等于 0
  • $i 小于等于 count($data)-1 时(所以2-1 = 1,我们应该循环两次)
  • 显示此元素的 ID 和温度值
  • $i 加一

我在思考或做错了什么吗?

此外,当我将 $i 初始化为 1 而不是 0 时,我可以获得我的 $data 数组中第二个条目的值。

Morris.js Chart 2

(我更喜欢说我不是开发人员,因此此代码可能不是最简洁的,我同意)

编辑:

  • Pastebin to the var_dump of $data : http://pastebin.com/dYNtLxqX

  • Screenshot when using Forbs' solution (Chart doesn't load at all) : Morris.js Chart 3

  • The SQL query I am using to populate $data Array :

    select iddevice, data.ip, type, description,
       avg(case when hour(date) = 00 then temp end) as temp_00,
       avg(case when hour(date) = 01 then temp end) as temp_01,
       avg(case when hour(date) = 02 then temp end) as temp_02,
       ...
       avg(case when hour(date) = 22 then temp end) as temp_22,
       avg(case when hour(date) = 23 then temp end) as temp_23
    from data, device
    where date >= '2017-03-20' and
      date < '2017-03-21' and
      device.ip = data.ip
    group by ip
    order by iddevice;
    
  • The Array is populate with this query using a while loop

    $results = $conn->query($sql);
    $k = 0;
    $data = array();
    while ($row = $results->fetch_assoc()) {
        $data[$k]['temp_00'] = $row['temp_00'];
        $data[$k]['temp_01'] = $row['temp_01'];
        $data[$k]['temp_02'] = $row['temp_02'];
        $data[$k]['temp_03'] = $row['temp_03'];
        ...
        $k++;
    }
    

请在您的$data变量上发布一个var_dump - Wes Foster
1
你正在使用 $s 而不是 $i$data[$s]['temp_00'],也许这就是问题所在。 - Titus
我已经更新了帖子;这个$i / $s的错误是由于我尝试了很多故障排除,但不幸的是它并不是问题所在。我还添加了一个pastebin到Array var_dump中。 - Will
$row 是从哪里来的呢?是从数据库查询吗?如果你能添加一点更多的代码来展示 $row 如何被填充,我可以向你展示一种不同的将数据从 PHP 传递到 JS 的方法,这可能会更容易。 - Don't Panic
我已经更新了主贴,其中包含我用来填充$data数组的SQL查询。但是因为当我手动执行echo $data[0]['id']echo $data[1]['temp_00']时,我可以访问到存储在$data数组中的值,所以我认为它们没有关联 :/ - Will
显示剩余2条评论
3个回答

2
这是我另一种处理方法的建议。它可以减少重复代码,并且最小化PHP/JS混合。
首先,在获取查询结果行时,以不同的方式构建数组:
while ($row = $results->fetch_assoc()) {
    // Loop over each of the temp_x columns
    for ($i=0; $i < 4; $i++) {
        $x = str_pad($i, 2, '0', STR_PAD_LEFT);
        // add the value for each temp_x to a temporary array, using time for a key
        $temp = is_null($row["temp_$x"]) ? 'null' : round($row["temp_$x"], 2);
        $times[$x][] = $row['iddevice'] . ':' . $temp;
    }
}

接下来,对临时数组中每个数组的值进行格式化。
foreach ($times as $time => $temps) {
    $data[] = "{ y: '{$time}h', " . implode(', ', $temps) . '}';
}

然后将$data数组转换为字符串:
$data = implode(",\n", $data);

那么,在JS部分所需的所有PHP代码如下:
Morris.Line({
  element: 'morris-area-chart',
  data: [ <?php echo $data ?> ]

使用json_encode可能会有更好的方法。如果您稍微更改从数据库中获取行的while循环内的代码:

for ($i=0; $i < 4; $i++) {
    $x = str_pad($i, 2, '0', STR_PAD_LEFT);
    $temp = is_null($row["temp_$x"]) ? null : round($row["temp_$x"], 2);
    $times[$x]['y'] = $x.'h';
    $times[$x][$row['iddevice']] = $temp;
}

然后可以使用json_encode来形成$data。(使用array_values将数组重新索引为数字索引,以便在JSON输出中呈现为数组而不是对象。)

$data = json_encode(array_values($times));

在JS中:

Morris.Line({
  element: 'morris-area-chart',
  data: <?php echo $data ?>
  // note: no [] brackets around $data in this version

无论这是否有效取决于所有键都可以是字符串,因为JSON键是字符串,所以您将获得如下输出
{ "y": "01", "1": 17.62, "2": 19.52 }

代替

{ y: '01', 1: 17.62, 2: 19.52 }

我认为它可能仍然可用。

希望我能给你多个赞!你真是个天才,非常感谢你提供的解决方案!最后一件事:我的数据库中有一些null值(请查看主贴中的pastebin),我希望这些null值在morris图表中被设置为"null"而不是"0"(目前的情况),这样可以防止线条下降到零并且根本不绘制该线条。 - Will
@William,我更新了那个答案。实际上,我刚刚意识到有更好的方法。我会在一分钟内再次编辑。 - Don't Panic
不,你是对的,XerXeX。@William我更新了答案以修复那个错别字。我还添加了另一种可能的方法,使用json_encode来完成它。 - Don't Panic
图表加载了,但是使用第二种方法没有值,因此在使用morris.js时可能需要不使用字符串作为键(或者我做错了什么,我不知道)。无论如何,使用您提供的第一种解决方案,它能够完美地工作,现在我可以在我的项目中继续前进了!非常感谢您的帮助,我的救星 ;) - Will
@JaredFarrish 我同意,我已经添加了一个部分到答案中以这种方式实现。我只是不确定它是否能够正确地处理json_encode生成的字符串键而不是原始代码中使用的整数键。事实上,我在事后进行了测试,它确实可以工作,但是OP出于某种原因遇到了一些麻烦。 - Don't Panic
显示剩余3条评论

0

你的问题在于循环中

while ($i <= count($data)-1)

这应该是

while ($i <= (count($data)-1))

或者

while ($i < count($data))

效果更好


很不幸,它不起作用;我已经尝试了所有这些解决方案,但没有一个是有效的。 - Will
当您使用这些数据时,您看到了什么?您能复制最终的PHP输出吗?只需要Morris相关内容。 - Forbs
我已经编辑了主贴,并附上了使用您的解决方案时输出的屏幕截图。 - Will
那是PHP代码,我指的是在运行后屏幕输出的内容(在源代码中)。 - Forbs
好的,我需要一分钟的时间来将代码恢复成你的解决方案并截取屏幕截图,然后编辑帖子 :) - Will
抱歉,我指的是在浏览器中显示类似于$(function() {Morris.Line({ element: 'morris-area-chart', data: [ { y: '00h', 1:57, 2:41}, { y: '01h', 1:62, 2:98}, { y: '02h', 1:44, 2:43}, { y: '03h', 1:67, 2:84}, ]}的代码。 - Forbs

0

你甚至可以进一步优化它。

  Morris.Line({
  element: 'morris-area-chart',
    data: [
    <?php
        foreach($data as $sensor) {
            foreach($sensor as $key => $value) {
                if($key == 'id') {
                    $id = $value;
                } else {
                    $tempTime[$key][$id] = $value;
                }
            }
        }   
        $i = 0;
        foreach($tempTime as $time) {
            echo sprintf("{ y: '%02dh', ",$i);
            foreach($time as $key => $value) {
                echo sprintf("%d:%d, ",$key, round($value,2);
            }
            echo "},";
            $i++;
        }
    ?>
  ],
  xkey: 'y',
  parseTime:false,
  ykeys: [1,2,3],
  pointSize: 2,
  hideHover: 'auto',
  labels: ['Capteur X', 'Capteur Y']
});

这样,如果你的数组变得很大,你就不必重复自己。

解释: foreach 是一个遍历数组的函数。 第一个 foreach 循环只是重新排列数组,以便在最后一个 foreach 循环中更容易使用(当你从 sql 创建数组时,你应该正确地执行此操作,但我无法从你的帖子中看出如何执行此操作)。 最后一个 foreach 循环只是打印出 Morris.line() 函数所需的字符串。希望这有意义。


你介意解释一下这段代码是如何工作的吗?我可以在我的图表上得到两条线,但那不是正确的值,所以我想看看哪里出了问题。正如所说,我不是一个程序员,也不熟悉foreach循环。 - Will
我已经编辑了答案。输出是什么?哪里出了问题? - XerXeX
谢谢您的解释。我认为错误与值的顺序有关,因为我的数据库中一些null值被设置成了图表上的某些值,反之亦然。无论如何,使用"Don't Panic"的解决方案可以正常工作,但我很感激您花时间帮助我 :) - Will

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接