Skip to content

Instantly share code, notes, and snippets.

@k-holy
Created January 26, 2012 16:13
Show Gist options
  • Save k-holy/1683549 to your computer and use it in GitHub Desktop.
Save k-holy/1683549 to your computer and use it in GitHub Desktop.
SplFileObject + CallbackFilterIterator(PHP5.4)
<?php
namespace Acme;
// SPLのファイル処理クラスSplFileObjectとPHP5.4のCallbackFilterIteratorを試してみる
class U {
public static function H($data, $default = null) {
if (isset($data)) {
return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
}
return $default;
}
}
class FilterableFileIterator extends \SplFileObject
{
protected $filter = null;
public function __set($name, $value)
{
if (strcmp('filter', $name) === 0) {
if (!is_callable($value)) {
throw new \InvalidArgumentException('The filter is not callable.');
}
$this->filter = $value;
return;
}
throw new \RuntimeException(sprintf('The field "%s" not defined.', $name));
}
public function current()
{
$item = parent::current();
if (isset($this->filter)) {
$item = call_user_func($this->filter, $item, $this->key());
}
return $item;
}
}
$csv_iterator = new FilterableFileIterator('php://memory', 'r+');
$csv_iterator->filter = function($item, $key) {
if (!is_array($item)) {
throw new \RuntimeException(sprintf('Invalid data found at line %d', $key));
}
$user = new \Stdclass();
$user->id = (isset($item[0])) ? mb_convert_encoding(trim($item[0]), 'UTF-8', 'SJIS') : null;
$user->name = (isset($item[1])) ? mb_convert_encoding(trim($item[1]), 'UTF-8', 'SJIS') : null;
$user->comment = (isset($item[2])) ? mb_convert_encoding($item[2], 'UTF-8', 'SJIS') : null;
return $user;
};
$csv_text = <<< CSV_TEXT
1,田中,
a,不正なID,
2,"小林""",コメント
3,長い名前長い名前長い名前,
4,"鈴木,","改行
改行
改行"
5,長井,とても長いコメントとても長いコメントとても長いコメントとても長いコメントとても長いコメント
CSV_TEXT;
$csv_text = mb_convert_encoding(str_replace("\n", "\r\n", $csv_text), 'SJIS', 'UTF-8');
$csv_iterator->fwrite($csv_text);
$csv_iterator->rewind();
$csv_iterator->setFlags(\SplFileObject::READ_CSV);
$csv_iterator->setCsvControl(',', '"');
$validator = function($user) {
if (strlen($user->id) === 0) {
return false;
}
if (!ctype_digit($user->id)) {
return false;
}
if (strlen($user->name) === 0) {
return false;
}
if (mb_strlen($user->name) > 10) {
return false;
}
if (mb_strlen($user->comment) > 20) {
return false;
}
return true;
};
$valid_users = new \CallbackFilterIterator($csv_iterator, function($user) use ($validator) {
return $validator($user);
});
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<style type="text/css">
table {
width:80%;
border-collapse:collapse;
margin:5px 0px;
}
caption {
text-align:left;
font-weight:bold;
}
th, td {
padding:2px;
border:solid 1px #999999;
}
tr.row1 {
background-color:#ffffcc;
}
tr.row2 {
background-color:#cccccc;
}
td.id {
width:5%;
text-align:right;
}
td.name {
width:30%;
text-align:left;
}
td.comment {
width:65%;
text-align:left;
white-space:pre;
}
</style>
</head>
<body>
<table>
<caption>Valid Users</caption>
<thead>
<tr>
<th>ID</th>
<th>名前</th>
<th>コメント</th>
</tr>
</thead>
<tbody>
<?php $number = 0;?>
<?php foreach ($valid_users as $user) : ?>
<tr class="row<?=(($number & 1) == 0) ? '1' : '2'?>">
<td class="id"><?=U::H($user->id)?></td>
<td class="name"><?=U::H($user->name)?></td>
<td class="comment"><?=U::H($user->comment)?></td>
</tr>
<?php $number++; ?>
<?php endforeach ?>
</tbody>
</table>
<table>
<caption>All Users</caption>
<thead>
<tr>
<th>ID</th>
<th>名前</th>
<th>コメント</th>
</tr>
</thead>
<tbody>
<?php $number = 0;?>
<?php foreach ($csv_iterator as $user) : ?>
<tr class="row<?=(($number & 1) == 0) ? '1' : '2'?>">
<td class="id"><?=U::H($user->id)?></td>
<td class="name"><?=U::H($user->name)?></td>
<td class="comment"><?=U::H($user->comment)?></td>
</tr>
<?php $number++; ?>
<?php endforeach ?>
</tbody>
</table>
</body>
</html>
@k-holy
Copy link
Author

k-holy commented Jan 26, 2012

ファイルハンドルを扱えるイテレータないの?って思ったら、SplFileObjectがSplFileInfoのイテレータ実装版だったという…。
普段はあまりSPL使ってないので知らなかったです(´・ω・`)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment