Completed
Push — master ( c9812e...73d93a )
by Ryuichi
02:42
created

StringInputStream::read()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 42
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 42
rs 6.7272
cc 7
eloc 21
nc 7
nop 1
1
<?php
2
namespace WebStream\IO;
3
4
use WebStream\Exception\Extend\InvalidArgumentException;
5
use WebStream\Exception\Extend\IOException;
6
7
/**
8
 * StringInputStream
9
 * @author Ryuichi TANAKA.
10
 * @since 2016/02/07
11
 * @version 0.7
12
 */
13
class StringInputStream extends InputStream
14
{
15
    /**
16
     * @var int 文字列長
17
     */
18
    private $length;
19
20
    /**
21
     * @var bool 終端かどうか
22
     */
23
    private $isEOF = false;
24
25
    /**
26
     * construct
27
     * @param string $str 文字列
28
     */
29
    public function __construct($str)
30
    {
31
        parent::__construct($str);
32
        $this->length = strlen($str);
33
    }
34
35
    /**
36
     * 入力ストリームを閉じる
37
     */
38
    public function close()
39
    {
40
        $this->stream = null;
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function read($length = null)
47
    {
48
        if ($this->stream === null) {
49
            return null;
50
        }
51
52
        if ($this->eof()) {
53
            return null;
54
        }
55
56
        // SkipでポインタをずらしただけではEOFにはならない、FileInputStream実装に合わせる
57
        // Skipでずらしたあとreadすると空文字を返し、もう一度readするとEOFを認識する
58
        // ファイルの終端より先にポインタをすすめることは「可能」=書き込みと同じ
59
        // なので、現在の終端位置より先に進めてもEOF自体にはならない。進めた位置はEOFのひとつ前
60
        // だからもう一回readするとEOFに到達する。なのでskipを使ってもEOF到達できない
61
        if ($this->cursorPosition > $this->length - 1) {
62
            $this->isEOF = true;
63
64
            return "";
65
        }
66
67
        $out = "";
0 ignored issues
show
Unused Code introduced by
$out is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
68
        if ($length === null) {
69
            $length = 1;
0 ignored issues
show
Unused Code introduced by
$length is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
70
            $out = substr($this->stream, $this->cursorPosition, 1);
71
            $this->cursorPosition += 1;
72
        } else {
73
            if (!is_int($length)) {
74
                throw new InvalidArgumentException("Stream read must be a numeric value.");
75
            }
76
77
            // $lengthがファイル終端を越えないようにする
78
            if (($this->cursorPosition + $length) > $this->length) {
79
                $length = $this->length - $this->cursorPosition;
80
            }
81
82
            $out = substr($this->stream, $this->cursorPosition, $length);
83
            $this->cursorPosition += $length;
84
        }
85
86
        return $out;
87
    }
88
89
    /**
90
     * 入力ストリームから行単位でデータを読み込む
91
     * 末尾に改行コードは含まない
92
     * @return string 読み込みデータ
93
     */
94
    public function readLine()
95
    {
96
        if ($this->stream === null) {
97
            return null;
98
        }
99
100
        if ($this->eof()) {
101
            return null;
102
        }
103
104
        // 処理対象の残りのバイト数
105
        $targetLength = $this->length - $this->cursorPosition;
106
107
        // 処理対象の文字列
108
        $text = substr($this->stream, $this->cursorPosition, $targetLength);
109
        $lengthEOL = strlen(PHP_EOL);
110
        $notLinePart = strstr($text, PHP_EOL);
111
112
        $notLinePartLength = 0;
113
        if ($notLinePart !== false) {
114
            $notLinePartLength = strlen($notLinePart);
115
        }
116
117
        $offset = $targetLength - $notLinePartLength;
118
        $out = substr($text, 0, $offset);
119
        $out = $out === false ? null : $out;
120
        $this->skip($offset + $lengthEOL);
121
122
        return $out;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function skip(int $pos)
129
    {
130
        if ($this->stream === null) {
131
            return -1;
132
        }
133
134
        // ファイル終端到達後、skipを実行すると後方にポインタが移動する
135
        // このときEOFだったものがEOFでなくなる
136
        $start = $this->cursorPosition;
137
138
        // 現在位置が負になった場合は-1を返して終了
139
        if ($this->cursorPosition + $pos < 0) {
140
            return -1;
141
        }
142
143
        $this->cursorPosition += $pos;
144
        $this->isEOF = false;
145
146
        // skipした実際のバイト数
147
        $skipNum = 0;
0 ignored issues
show
Unused Code introduced by
$skipNum is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
148 View Code Duplication
        if ($start > $this->cursorPosition) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
149
            // 後方へ移動
150
            $skipNum = $start - $this->cursorPosition;
151
        } else {
152
            // 前方へ移動
153
            $skipNum = $this->cursorPosition - $start;
154
        }
155
156
        return $skipNum;
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function eof()
163
    {
164
        return $this->isEOF;
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170
    public function isMarkSupported()
171
    {
172
        return true;
173
    }
174
}
175