Completed
Push — master ( df6cea...869caa )
by Alexander
60:24 queued 35:17
created

StreamMetaData::__set()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 5
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 6
1
<?php
2
declare(strict_types = 1);
3
/*
4
 * Go! AOP framework
5
 *
6
 * @copyright Copyright 2012, Lisachenko Alexander <[email protected]>
7
 *
8
 * This source file is subject to the license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Go\Instrument\Transformer;
13
14
use Go\Instrument\PathResolver;
15
use Go\ParserReflection\ReflectionEngine;
16
use InvalidArgumentException;
17
use PhpParser\Node;
18
use function is_array, is_resource;
19
20
/**
21
 * Stream metadata object
22
 *
23
 * @property-read string $source
24
 */
25
class StreamMetaData
26
{
27
    /**
28
     * Mapping between array keys and properties
29
     *
30
     * @var array
31
     */
32
    private static $propertyMap = [
33
        'stream_type'  => 'streamType',
34
        'wrapper_type' => 'wrapperType',
35
        'wrapper_data' => 'wrapperData',
36
        'filters'      => 'filterList',
37
        'uri'          => 'uri',
38
    ];
39
40
    /**
41
     * A label describing the underlying implementation of the stream.
42
     *
43
     * @var string
44
     */
45
    public $streamType;
46
47
    /**
48
     * A label describing the protocol wrapper implementation layered over the stream.
49
     *
50
     * @var string
51
     */
52
    public $wrapperType;
53
54
    /**
55
     * Wrapper-specific data attached to this stream.
56
     *
57
     * @var mixed
58
     */
59
    public $wrapperData;
60
61
    /**
62
     * Array containing the names of any filters that have been stacked onto this stream.
63
     *
64
     * @var array
65
     */
66
    public $filterList;
67
68
    /**
69
     * The URI/filename associated with this stream.
70
     *
71
     * @var string
72
     */
73
    public $uri;
74
75
    /**
76
     * Information about syntax tree
77
     *
78
     * @var Node[]
79
     */
80
    public $syntaxTree;
81
82
    /**
83
     * List of source tokens
84
     *
85
     * @var array
86
     */
87
    public $tokenStream = [];
88
89
    /**
90
     * Creates metadata object from stream
91
     *
92
     * @param resource $stream Instance of stream
93
     * @param string $source Source code or null
94
     * @throws \InvalidArgumentException for invalid stream
95
     */
96 34
    public function __construct($stream, string $source = null)
97
    {
98 34
        if (!is_resource($stream)) {
99
            throw new InvalidArgumentException('Stream should be valid resource');
100
        }
101 34
        $metadata = stream_get_meta_data($stream);
102 34
        if (preg_match('/resource=(.+)$/', $metadata['uri'], $matches)) {
103 8
            $metadata['uri'] = PathResolver::realpath($matches[1]);
104
        }
105 34
        foreach ($metadata as $key => $value) {
106 34
            if (!isset(self::$propertyMap[$key])) {
107 34
                continue;
108
            }
109 34
            $mappedKey = self::$propertyMap[$key];
110 34
            $this->$mappedKey = $value;
111
        }
112 34
        $this->syntaxTree = ReflectionEngine::parseFile($this->uri, $source);
113 34
        $this->setTokenStreamFromRawTokens(ReflectionEngine::getLexer()->getTokens());
114 34
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119 34
    public function __get($name)
120
    {
121 34
        if ($name === 'source') {
122 34
            return $this->getSource();
123
        }
124
125
        return null;
126
    }
127
128
    /**
129
     * @inheritDoc
130
     */
131
    public function __set($name, $value)
132
    {
133
        if ($name === 'source') {
134
            trigger_error('Setting StreamMetaData->source is deprecated, use tokenStream instead', E_USER_DEPRECATED);
135
            $this->setSource($value);
136
        }
137
    }
138
139
    /**
140
     * Returns source code directly from tokens
141
     */
142 34
    private function getSource(): string
143
    {
144 34
        $transformedSource = '';
145 34
        foreach ($this->tokenStream as $token) {
146 34
            $transformedSource .= $token[1] ?? $token;
147
        }
148
149 34
        return $transformedSource;
150
    }
151
152
    /**
153
     * Sets the new source for this file
154
     *
155
     * @TODO: Unfortunately, AST won't be changed, so please be accurate during transformation
156
     *
157
     * @param string $newSource
158
     */
159 34
    private function setSource(string $newSource): void
160
    {
161 34
        $rawTokens = token_get_all($newSource);
162 34
        $this->setTokenStreamFromRawTokens($rawTokens);
163 34
    }
164
165 34
    /**
166
     * Sets an array of token identifiers for this file
167
     *
168
     * @param array $rawTokens
169
     */
170
    public function setTokenStreamFromRawTokens($rawTokens): void
171
    {
172
        foreach ($rawTokens as $index => $rawToken) {
173
            $this->tokenStream[$index] = is_array($rawToken) ? $rawToken : [T_STRING, $rawToken];
174
        }
175
    }
176
}
177