/
SourceTransformingLoader.php
150 lines (129 loc) · 3.67 KB
/
SourceTransformingLoader.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
/**
* Go! AOP framework
*
* @copyright Copyright 2011, Lisachenko Alexander <lisachenko.it@gmail.com>
*
* This source file is subject to the license that is bundled
* with this source code in the file LICENSE.
*/
namespace Go\Instrument\ClassLoading;
use php_user_filter as PhpStreamFilter;
use Go\Instrument\Transformer\StreamMetaData;
use Go\Instrument\Transformer\SourceTransformer;
use Go\Instrument\Transformer\FilterInjectorTransformer;
/**
* Php class loader filter for processing php code
*/
class SourceTransformingLoader extends PhpStreamFilter implements LoadTimeWeaver
{
/**
* Php filter definition
*/
const PHP_FILTER_READ = 'php://filter/read=';
/**
* Default PHP filter name for registration
*/
const FILTER_IDENTIFIER = 'go.source.transforming.loader';
/**
* String buffer
*
* @var string
*/
protected $data = '';
/**
* List of transformers
*
* @var array|SourceTransformer[]
*/
protected static $transformers = array();
/**
* Identifier of filter
*
* @var string
*/
protected static $filterId;
/**
* Register current loader as stream filter in PHP
*
* @param string $filterId Identifier for the filter
* @throws \RuntimeException If registration was failed
*/
public function register($filterId = self::FILTER_IDENTIFIER)
{
if (!empty(self::$filterId)) {
throw new \RuntimeException('Stream filter already registered');
}
$result = stream_filter_register($filterId, __CLASS__);
if (!$result) {
throw new \RuntimeException('Stream filter was not registered');
}
self::$filterId = $filterId;
}
/**
* Returns the name of registered filter
*
* @throws \RuntimeException if filter was not registered
* @return string
*/
public function getId()
{
if (empty(self::$filterId)) {
throw new \RuntimeException('Stream filter was not registered');
}
return self::$filterId;
}
/**
* {@inheritdoc}
*/
public function filter($in, $out, &$consumed, $closing)
{
while ($bucket = stream_bucket_make_writeable($in)) {
$this->data .= $bucket->data;
}
if ($closing || feof($this->stream)) {
$consumed = strlen($this->data);
// $this->stream contains pointer to the source
$metadata = new StreamMetaData($this->stream, $this->data);
$this->transformCode($metadata);
$bucket = stream_bucket_new($this->stream, $metadata->source);
stream_bucket_append($out, $bucket);
return PSFS_PASS_ON;
}
return PSFS_FEED_ME;
}
/**
* Adds a SourceTransformer to be applied by this LoadTimeWeaver.
*
* @param $transformer SourceTransformer Transformer for source code
*
* @return void
*/
public function addTransformer(SourceTransformer $transformer)
{
self::$transformers[] = $transformer;
}
/**
* Load source file with transformation
*
* @param string $source Original source name
*
* @return mixed
*/
public function load($source)
{
return include FilterInjectorTransformer::rewrite($source);
}
/**
* Transforms source code by passing it through all transformers
*
* @param StreamMetaData|null $metadata Metadata from stream
* @return void
*/
protected function transformCode(StreamMetaData $metadata)
{
foreach (self::$transformers as $transformer) {
$transformer->transform($metadata);
}
}
}