StreamLexer::peekNextToken()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 11
rs 10
1
<?php declare(strict_types=1);
2
/**
3
 * portable-game-notation (https://github.com/chesszebra/portable-game-notation)
4
 *
5
 * @link https://github.com/chesszebra/portable-game-notation for the canonical source repository
6
 * @copyright Copyright (c) 2017 Chess Zebra (https://chesszebra.com)
7
 * @license https://github.com/chesszebra/portable-game-notation/blob/master/LICENSE.md MIT
8
 */
9
10
namespace ChessZebra\PortableGameNotation\Lexer;
11
12
use ChessZebra\PortableGameNotation\Token\TokenInterface;
13
use ChessZebra\PortableGameNotation\Lexer\Exception\InvalidTokenException;
14
use InvalidArgumentException;
15
16
/**
17
 * Reads PGN games from a stream.
18
 */
19
final class StreamLexer extends AbstractLexer
20
{
21
    /**
22
     * @var resource
23
     */
24
    private $stream;
25
26
    /**
27
     * Initializes a new instance of this class.
28
     *
29
     * @param resource $stream The stream to read from.
30
     * @throws InvalidArgumentException Thrown when the stream is invalid.
31
     */
32
    public function __construct($stream)
33
    {
34
        parent::__construct();
35
36
        if (!is_resource($stream)) {
37
            throw new InvalidArgumentException('Invalid stream provided.');
38
        }
39
40
        $this->stream = $stream;
41
    }
42
43
    public function getOffset()
44
    {
45
        $position = ftell($this->stream);
46
47
        if ($this->buffer) {
48
            $position -= strlen($this->buffer);
49
        }
50
51
        return $position;
52
    }
53
54
    /**
55
     * Gets the next token from the lexer.
56
     *
57
     * @return TokenInterface|null
58
     * @throws InvalidTokenException
59
     */
60
    public function getNextToken(): ?TokenInterface
61
    {
62
        if (feof($this->stream)) {
63
            return null;
64
        }
65
66
        // Make sure the buffer is always filled.
67
        if (!$this->buffer || strlen($this->buffer) < 4096) {
68
            $this->buffer .= fread($this->stream, 4096);
69
        }
70
71
        return parent::getNextToken();
72
    }
73
74
    /**
75
     * Peeks in the stream what the next token will be.
76
     *
77
     * @return TokenInterface|null
78
     * @throws InvalidTokenException
79
     */
80
    public function peekNextToken(): ?TokenInterface
81
    {
82
        $offset = ftell($this->stream);
83
        $buffer = $this->buffer;
84
85
        $token = $this->getNextToken();
86
87
        fseek($this->stream, $offset);
88
        $this->buffer = $buffer;
89
90
        return $token;
91
    }
92
}
93