Skip to content

Instantly share code, notes, and snippets.

@Leko
Last active August 29, 2015 14:23
Show Gist options
  • Save Leko/f2b090fe14f51dbea841 to your computer and use it in GitHub Desktop.
Save Leko/f2b090fe14f51dbea841 to your computer and use it in GitHub Desktop.
PHPでもRubyみたいに..や...で範囲アクセスしたかった...おまけでインデックスの反転も実装しています。
<?php
class Ary implements \ArrayAccess
{
protected $list;
public function __construct(/* $args... */)
{
$this->list = func_get_args();
}
public function offsetExists($offset)
{
// Undefined offset ** を渡された値にするため0以上になる場合のみインデックスを逆転する
if(is_int($offset) && $offset < 0 && $offset + count($this->list) >= 0) {
$offset += count($this->list);
}
return isset($this->list[$offset]);
}
public function offsetGet($offset)
{
list($from, $to) = $this->parseOffset($offset);
if($from === $to) {
$ret = $this->list[$from];
} else {
$ret = array();
for($ii = $from; $ii <= $to; $ii++) $ret[] = $this->list[$ii];
}
return $ret;
}
public function offsetSet($offset, $value)
{
list($from, $to) = $this->parseOffset($offset);
if($from === $to) {
$this->list[$from] = $value;
} elseif(is_array($value)) {
for($ii = $from; $ii <= $to; $ii++) $this->list[$ii] = $value[$ii - $from];
} else {
for($ii = $from; $ii <= $to; $ii++) $this->list[$ii] = $value;
}
}
public function offsetUnset($offset)
{
list($from, $to) = $this->parseOffset($offset);
if($from === $to) {
unset($this->list[$from]);
} else {
for($ii = $from; $ii <= $to; $ii++) unset($this->list[$ii]);
}
}
private function parseOffset($offset)
{
// Undefined offset ** を渡された値にするため0以上になる場合のみインデックスを逆転する
if(is_int($offset) && $offset < 0 && $offset + count($this->list) >= 0) {
$offset += count($this->list);
}
if(is_string($offset) && strpos($offset, '..') >= 0) {
preg_match('/^([0-9]+)(\.\.\.?)([0-9]+)$/', $offset, $matches);
list($_, $from, $op, $to) = $matches;
if($op === '..') $to--;
return [$from, $to];
} else {
return [$offset, $offset];
}
}
}
// PHPのarray()と同じように中の要素を列挙して可変長引数として渡す
$list = new Ary(1, 2, 3, 4, 5);
// 普通の添字アクセス1
var_dump(isset($list[1]), $list[1]);
echo '------------'.PHP_EOL;
// 普通の添字アクセス2
var_dump(isset($list[0]), $list[0]);
echo '------------'.PHP_EOL;
// マイナス添字でのアクセス1(後ろから見る)
var_dump(isset($list[-1]), $list[-1]);
echo '------------'.PHP_EOL;
// マイナス添字でのアクセス2(後ろから見る)
var_dump(isset($list[-5]), $list[-5]);
echo '------------'.PHP_EOL;
// マイナスでも存在しない添字に遭遇した場合Noticeが出る
var_dump(isset($list[-6]), $list[-6]);
echo '------------'.PHP_EOL;
// .. = 1以上3未満の範囲アクセス
var_dump($list['1..3']);
echo '------------'.PHP_EOL;
// ... = 1以上3以下の範囲アクセス
var_dump($list['1...3']);
echo '------------'.PHP_EOL;
// ...を使用した一括代入。配列を指定すると各要素に対応する値を入れる
$list['1...3'] = [20, 30, 40];
var_dump($list);
echo '------------'.PHP_EOL;
// 範囲ごとの一括指定が可能。配列以外の値を指定すると範囲内全てがその値に
$list['1..3'] = 1000;
var_dump($list);
echo '------------'.PHP_EOL;
// 一括unset
unset($list['3..5']);
var_dump($list);
echo '------------'.PHP_EOL;
bool(true)
int(2)
------------
bool(true)
int(1)
------------
bool(true)
int(5)
------------
bool(true)
int(1)
------------
PHP Notice: Undefined offset: -6 in /Users/SYS-INOUE/Downloads/range.php on line 27
PHP Stack trace:
PHP 1. {main}() /Users/SYS-INOUE/Downloads/range.php:0
PHP 2. Ary->offsetGet() /Users/SYS-INOUE/Downloads/range.php:93
Notice: Undefined offset: -6 in /Users/SYS-INOUE/Downloads/range.php on line 27
Call Stack:
0.0005 256088 1. {main}() /Users/SYS-INOUE/Downloads/range.php:0
0.0013 257648 2. Ary->offsetGet() /Users/SYS-INOUE/Downloads/range.php:93
bool(false)
NULL
------------
array(2) {
[0] =>
int(2)
[1] =>
int(3)
}
------------
array(3) {
[0] =>
int(2)
[1] =>
int(3)
[2] =>
int(4)
}
------------
class Ary#1 (1) {
protected $list =>
array(5) {
[0] =>
int(1)
[1] =>
int(20)
[2] =>
int(30)
[3] =>
int(40)
[4] =>
int(5)
}
}
------------
class Ary#1 (1) {
protected $list =>
array(5) {
[0] =>
int(1)
[1] =>
int(1000)
[2] =>
int(1000)
[3] =>
int(40)
[4] =>
int(5)
}
}
------------
class Ary#1 (1) {
protected $list =>
array(3) {
[0] =>
int(1)
[1] =>
int(1000)
[2] =>
int(1000)
}
}
------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment