【问题标题】:PHP Passing an array to pack() functionPHP将数组传递给pack()函数
【发布时间】:2015-04-28 12:16:48
【问题描述】:

pack() 语法是(来自http://php.net/manual/en/function.pack.php

string pack ( string $format [, mixed $args [, mixed $... ]] )

所以假设我需要打包三个字节

$packed = pack( "c*", 65, 66, 67 );

但是如果我必须打包任意数量的字节呢?

它们可以方便地存储到一个数组中,所以我天真地尝试了

$a = array( 65, 66, 67 );
$packed = pack( "c*", $a );

但它不起作用。

有没有办法让pack() 使用数组?

【问题讨论】:

  • 我认为这对你有帮助:stackoverflow.com/a/5473057/3933332
  • 当稍后在问题中未指定 php5.6 时给出 php5.6+ 特定答案时,不接受 php 的工作答案并不好:)...我的巫毒娃娃几乎是完成。

标签: php arrays pack


【解决方案1】:

晚了一点,但为了将来参考,您可以使用新的 ... 运算符 (v5.6+) 来爆炸数组内联:

$packed = pack("c*", ...$a);

【讨论】:

    【解决方案2】:

    您可以创建自己的函数array_pack,使用call_user_funccall_user_func_array 函数在内部调用pack,这样您就可以将正确数量的参数传递给它。

    这样的事情可能会起作用(虽然没有经过测试......但你明白了一般的想法)

    function array_pack(array $arr) {
      return call_user_func_array("pack", array_merge(array("c*"), $arr));
    }
    

    【讨论】:

      【解决方案3】:

      使用字符串连接代替pack()

      当打包字节时,打包的二进制数据(字符串)可以通过简单地使用chr()、连接.foreach循环来生成:

      packed = "";
      foreach ( $a as $byte ) {
          $packed .= chr( $byte );
      }
      

      根据原始问题,$a 是源数组,$packed 是存储在字符串变量中的生成二进制数据。


      基准测试

      在撰写本文时,已经有了 5 种不同的工作解决方案,如果要打包的数据量很大,值得做一个基准测试。

      我已经使用 1048576 个元素的数组测试了这五个案例,以便生成 1 MB 的二进制数据。我测量了执行时间和消耗的内存。

      测试环境:PHP 5.6.30 - Mac OS X - 2.2 GHz Intel Core I7

      当然只使用一个核心

      // pack with ... operator:    57 ms - 1.3 MB
      // string concatentation:    197 ms - 1.3 MB
      // call_user_func_array:     249 ms - 1.5 MB
      // multiple pack:            298 ms - 1.3 MB
      // array_reduce:           39114 ms - 1.3 MB
      

      ... 运算符直接与 pack 函数一起使用,如果是迄今为止最快的解决方案 (accepted answer)

      如果... 不可用(PHP 5.6 之前的版本),this answer (string concatentation) 提出的解决方案是最快的。

      每种情况下的内存使用情况几乎相同。

      如果有人感兴趣,我会发布测试代码。


      <?php
      
      // Return elapsed time from epoch time in milliseconds
      
      function milliseconds() {
          $mt = explode(' ', microtime());
          return ((int)$mt[1]) * 1000 + ((int)round($mt[0] * 1000));
      }
      
      
      
      // Which test to run [1..5]
      
      $test = $argv[ 1 ];
      
      
      
      // Test 1024x1024 sized array
      
      $arr = array();
      for( $i = 0; $i < 1024 * 1024; $i++ )
      {
          $arr[] = rand( 0, 255 );
      }
      
      
      
      // Initial memory usage and time
      
      $ms0 = milliseconds();
      $mem0 = memory_get_usage( true );
      
      
      
      // Test 1: string concatentation
      
      if( $test == '1' )
      {
          $data = "";
          foreach ( $arr as $byte ) {
              $data .= chr( $byte );
          }
                  
          $test = "string concatentation";
      }
      
      
      
      // Test 2: call_user_func_array
      
      if( $test == '2' )
      {
          $data = call_user_func_array("pack", array_merge(array("c*"), $arr));
      
          $test = "call_user_func_array";
      }
      
      
      
      // Test 3: pack with ... operator
      
      if( $test == '3' )
      {
          $data = pack("c*", ...$arr);
      
          $test = "pack with ... operator";
      }
      
      
      
      // Test 4: array_reduce
      
      if( $test == '4' )
      {
          $data = array_reduce($arr, function($carry, $item) { return $carry .= pack('c', $item); });
      
          $test = "array_reduce";
      }
      
      
      
      // Test 5: Multiple pack
      
      if( $test == '5' )
      {
          $data = "";
          foreach ($arr as $item) $data .= pack("c", $item);
      
          $test = "multiple pack";
      }
      
      
      
      // Output result
      
      $ms = milliseconds() - $ms0;
      $mem = round( ( memory_get_usage( true ) - $mem0 ) / ( 1024 * 1024 ), 1 );
      echo "$test: $ms ms; $mem MB\n";
      

      【讨论】:

        【解决方案4】:

        我使用这个功能:

        private function pack_array($format, $arg)
        {
            $result="";
            foreach ($arg as $item) $result .= pack ($format, $item);
            return $result;
        }
        

        【讨论】:

          【解决方案5】:

          如果您不能使用... 运算符,另一种选择:

          $packed = array_reduce($a, function($carry, $item) {
              return $carry .= pack('c', $item);
          });
          

          【讨论】:

            猜你喜欢
            • 2012-07-19
            • 2013-01-16
            • 2012-06-01
            • 2013-07-05
            • 1970-01-01
            • 2017-11-07
            • 2020-07-28
            • 2011-06-20
            相关资源
            最近更新 更多