読者です 読者をやめる 読者になる 読者になる

URI::QueryParamのquery_paramよりquery_param_appendを使用した方がいい理由について

URI::QueryParam - Additional query methods for URIs

https://metacpan.org/pod/URI::QueryParam

perlにはURI::QueryParamというモジュールがありまして、URIモジュールだけだと
届かない痒いところに手が届くことをしてくれるモジュールです。

例えば、uriから特定のパラメータだけを削りたいとかそういう場合
URIだけだと面倒なんですが、URI::QueryParamがあれば割と簡単に消せます。

# uri_query.pl
use strict;
use warnings;
use URI;
use URI::QueryParam;

my $uri = URI->new('http://google.com/');
$uri->query_form( a => 1 );
warn $uri->as_string;
$uri->query_param_delete('a');
warn $uri->as_string;
http://google.com/?a=1 at uri_query.pl line 8.
http://google.com/ at uri_query.pl line 10.

その逆の追加もよろしくやってくれて
同一パラメータでもちゃんと追加対象にしてくれています。

# uri_query.pl
use strict;
use warnings;
use URI;
use URI::QueryParam;

my $uri = URI->new('http://google.com/');
$uri->query_form( a => 1 );
warn $uri->as_string;
$uri->query_param_append( a => 1 );
warn $uri->as_string;
http://google.com/?a=1 at uri_query.pl line 8.
http://google.com/?a=1&a=1 at uri_query.pl line 10.

問題は初期化時にどうすべきか?
ということでして、通常であればこういう感じにしてあげれば
メソッドの利用目的にも合っているのではないかと思うのですが、

# uri_query.pl
use strict;
use warnings;
use URI;
use URI::QueryParam;

sub add_default_param {
   my $uri = URI->new(shift);
   $uri->query_param_append( a => 1 );
   $uri->query_param_append( b => 1 );
   $uri->as_string;
}

warn add_uri_param('http://google.com/?hoge=1');

条件

  1. 渡される引数が想定可能であり、
  2. なおかつ同一パラメーターが無い

query_paramとどちらをおすすめすべきか?を定量的に返したい。

  1. 想定できない場合においてはquery_param_appendが正しいはず。
  2. 一応運用上の問題点を挙げるなら、安易にまねされるケースがあり得るなどがあげられます。
  3. とりあえずそこを無視した場合にquery_param_appendを推奨するに足る根拠が欲しい。
use strict;
use warnings;
use Benchmark qw(:all);
use URI;
use URI::QueryParam;

my $count = 100000;

timethese($count, {
   query_param        => sub {
         my $uri = URI->new('http://google.com/');
         $uri->query_param( a => 1 );
         $uri->query_param( b => 1 );
         $uri->query_param( c => 1 );
         $uri->query_param( d => 1 );
         $uri->query_param( f => 1 );
         $uri->as_string;
   },
   query_param_append => sub {
      my $uri = URI->new('http://google.com/');
      $uri->query_param_append( a => 1 );
      $uri->query_param_append( b => 1 );
      $uri->query_param_append( c => 1 );
      $uri->query_param_append( d => 1 );
      $uri->query_param_append( f => 1 );
      $uri->as_string;
   },
});

とりあえず、2回ほど試してみた。

Benchmark: timing 100000 iterations of query_param, query_param_append...
query_param: 17 wallclock secs (17.43 usr +  0.00 sys = 17.43 CPU) @ 5737.23/s (n=100000)
query_param_append: 14 wallclock secs (13.20 usr +  0.00 sys = 13.20 CPU) @ 7575.76/s (n=100000)

Benchmark: timing 100000 iterations of query_param, query_param_append...
query_param: 19 wallclock secs (18.46 usr +  0.00 sys = 18.46 CPU) @ 5417.12/s (n=100000)
query_param_append: 14 wallclock secs (14.27 usr +  0.01 sys = 14.28 CPU) @ 7002.80/s (n=100000)

appendの方が高速のようだ。いったんこの結果が一つの理由になるので𠮷とする。
ただ、内部的にどうなのか追いたいので後日追記します。(短いのである程度は判明してますが)