@@ -18,22 +18,22 @@ class Compressor
1818 const COMPRESS_TYPE_LOCAL_VARIABLES = 'local_variables ' ;
1919 const COMPRESS_TYPE_OBJECT_VARIABLES = 'object_variables ' ;
2020 const COMPRESS_TYPE_OBJECT_METHODS = 'object_methods ' ;
21-
21+
2222 protected $ content = '' ;
2323
24- protected $ whitespaces = false ;
24+ protected $ strip_whitespaces = false ;
2525
2626 protected $ comments = false ;
2727
2828 protected $ compress_types = [
29- 'local_variables ' => false ,
30- 'object_variables ' => false ,
31- 'object_methods ' => false ,
29+ 'local_variables ' => false ,
30+ 'object_variables ' => false ,
31+ 'object_methods ' => false ,
3232 ];
3333
3434 protected $ exclude_names = [
35- 'local_variables ' => [
36- 'this ' => 'this ' ,/** use in Object method scope **/
35+ 'local_variables ' => [
36+ 'this ' => 'this ' , /** use in Object method scope **/
3737 'GLOBALS ' => 'GLOBALS ' ,
3838 '_GET ' => '_GET ' ,
3939 '_POST ' => '_POST ' ,
@@ -44,11 +44,11 @@ class Compressor
4444 'http_response_header ' => 'http_response_header ' ,
4545 'php_errormsg ' => 'php_errormsg ' ,
4646 ],
47- 'object_variables ' => [
48- 'this ' => 'this ' ,
47+ 'object_variables ' => [
48+ 'this ' => 'this ' ,
4949 ],
50-
51- 'object_methods ' => [
50+
51+ 'object_methods ' => [
5252 //Magic
5353 'this ' => 'this ' ,
5454 '__construct ' => '__construct ' ,
@@ -69,7 +69,7 @@ class Compressor
6969 // only php 7
7070 'do ' => 'do ' ,
7171 'as ' => 'as ' ,
72- ]
72+ ],
7373 ];
7474 /**
7575 * @var NodeTraverser
@@ -82,34 +82,168 @@ public function __construct($data = [])
8282 }
8383
8484 public function compress ()
85- {
85+ {
8686 try {
8787 $ statements = $ this ->getStatements ();
8888 $ traverser = $ this ->getTraverser ();
8989 $ traverser ->addVisitor (new GlobalVisitor ($ this ->getCompressSettings ()));
9090 $ new_statements = $ traverser ->traverse ($ statements );
9191 $ this ->content = $ this ->getCompiller ()->prettyPrint ($ new_statements );
92+ if ($ this ->strip_whitespaces ) {
93+ $ this ->content = $ this ->stripWhitespaces ($ this ->content );
94+ }
9295 } catch (Error $ e ) {
9396 echo 'Parse Error: ' , $ e ->getMessage ();
9497 }
9598 }
99+
100+ protected function stripWhitespaces ($ code )
101+ {
102+ static $ IW = array (
103+ T_CONCAT_EQUAL , // .=
104+ T_DOUBLE_ARROW , // =>
105+ T_BOOLEAN_AND , // &&
106+ T_BOOLEAN_OR , // ||
107+ T_IS_EQUAL , // ==
108+ T_IS_NOT_EQUAL , // != or <>
109+ T_IS_SMALLER_OR_EQUAL , // <=
110+ T_IS_GREATER_OR_EQUAL , // >=
111+ T_INC , // ++
112+ T_DEC , // --
113+ T_PLUS_EQUAL , // +=
114+ T_MINUS_EQUAL , // -=
115+ T_MUL_EQUAL , // *=
116+ T_DIV_EQUAL , // /=
117+ T_IS_IDENTICAL , // ===
118+ T_IS_NOT_IDENTICAL , // !==
119+ T_DOUBLE_COLON , // ::
120+ T_PAAMAYIM_NEKUDOTAYIM , // ::
121+ T_OBJECT_OPERATOR , // ->
122+ T_DOLLAR_OPEN_CURLY_BRACES , // ${
123+ T_AND_EQUAL , // &=
124+ T_MOD_EQUAL , // %=
125+ T_XOR_EQUAL , // ^=
126+ T_OR_EQUAL , // |=
127+ T_SL , // <<
128+ T_SR , // >>
129+ T_SL_EQUAL , // <<=
130+ T_SR_EQUAL , // >>=
131+ );
132+ $ code = preg_replace ('/\s+/is ' , " " , $ code );
133+ $ tokens = token_get_all ($ code );
134+
135+ $ new = "" ;
136+ $ c = sizeof ($ tokens );
137+ $ iw = false ; // ignore whitespace
138+ $ ih = false ; // in HEREDOC
139+ $ ls = "" ; // last sign
140+ $ ot = null ; // open tag
141+ for ($ i = 0 ; $ i < $ c ; $ i ++) {
142+ $ token = $ tokens [$ i ];
143+ if (is_array ($ token )) {
144+ list ($ tn , $ ts ) = $ token ; // tokens: number, string, line
145+ $ tname = token_name ($ tn );
146+ if ($ tn == T_INLINE_HTML ) {
147+ $ new .= $ ts ;
148+ $ iw = false ;
149+ } else {
150+ if ($ tn == T_OPEN_TAG ) {
151+ if (strpos ($ ts , " " ) || strpos ($ ts , "\n" ) || strpos ($ ts , "\t" ) || strpos ($ ts , "\r" )) {
152+ $ ts = rtrim ($ ts );
153+ }
154+ $ ts .= " " ;
155+ $ new .= $ ts ;
156+ $ ot = T_OPEN_TAG ;
157+ $ iw = true ;
158+ } elseif ($ tn == T_OPEN_TAG_WITH_ECHO ) {
159+ $ new .= $ ts ;
160+ $ ot = T_OPEN_TAG_WITH_ECHO ;
161+ $ iw = true ;
162+ } elseif ($ tn == T_CLOSE_TAG ) {
163+ if ($ ot == T_OPEN_TAG_WITH_ECHO ) {
164+ $ new = rtrim ($ new , "; " );
165+ } else {
166+ $ ts = " " . $ ts ;
167+ }
168+ $ new .= $ ts ;
169+ $ ot = null ;
170+ $ iw = false ;
171+ } elseif (in_array ($ tn , $ IW )) {
172+ $ new .= $ ts ;
173+ $ iw = true ;
174+ } elseif ($ tn == T_CONSTANT_ENCAPSED_STRING
175+ || $ tn == T_ENCAPSED_AND_WHITESPACE
176+ ) {
177+ if ($ ts [0 ] == '" ' ) {
178+ $ ts = addcslashes ($ ts , "\n\t\r" );
179+ }
180+ $ new .= $ ts ;
181+ $ iw = true ;
182+ } elseif ($ tn == T_WHITESPACE ) {
183+ $ nt = @$ tokens [$ i + 1 ];
184+ if (!$ iw && (!is_string ($ nt ) || $ nt == '$ ' ) && !in_array ($ nt [0 ], $ IW )) {
185+ $ new .= " " ;
186+ }
187+ $ iw = false ;
188+ } elseif ($ tn == T_START_HEREDOC ) {
189+ $ new .= "<<<S \n" ;
190+ $ iw = false ;
191+ $ ih = true ; // in HEREDOC
192+ } elseif ($ tn == T_END_HEREDOC ) {
193+ $ new .= "S; " ;
194+ $ iw = true ;
195+ $ ih = false ; // in HEREDOC
196+ for ($ j = $ i + 1 ; $ j < $ c ; $ j ++) {
197+ if (is_string ($ tokens [$ j ]) && $ tokens [$ j ] == "; " ) {
198+ $ i = $ j ;
199+ break ;
200+ } else if ($ tokens [$ j ][0 ] == T_CLOSE_TAG ) {
201+ break ;
202+ }
203+ }
204+ } elseif ($ tn == T_COMMENT || $ tn == T_DOC_COMMENT ) {
205+ $ iw = true ;
206+ } else {
207+ if (!$ ih ) {
208+ //$ts = strtolower($ts);
209+ }
210+ $ new .= $ ts ;
211+ $ iw = false ;
212+ }
213+ }
214+ $ ls = "" ;
215+ } else {
216+ if (($ token != "; " && $ token != ": " ) || $ ls != $ token ) {
217+ $ new .= $ token ;
218+ $ ls = $ token ;
219+ }
220+ $ iw = true ;
221+ }
222+ }
223+
224+ return $ new ;
225+ }
96226
97- public function setExcludeNames ($ type = '' , array $ exclude_names ) {
98- if (isset ($ this ->compress_types [$ type ])) {
227+ public function setExcludeNames ($ type = '' , array $ exclude_names )
228+ {
229+ if (isset ($ this ->compress_types [$ type ])) {
99230 $ this ->exclude_names [$ type ] += $ exclude_names ;
100231 }
101232 }
233+
102234 protected function getCompressSettings ()
103235 {
104236 $ settings = [];
105237 foreach ($ this ->compress_types as $ type => $ enable ) {
106238 $ settings [$ type ] = [
107- 'enable ' => $ enable ,
108- 'exclude_names ' => $ this ->exclude_names [$ type ]
239+ 'enable ' => $ enable ,
240+ 'exclude_names ' => $ this ->exclude_names [$ type ],
109241 ];
110242 }
243+
111244 return $ settings ;
112245 }
246+
113247 public function getContent ()
114248 {
115249 return $ this ->content ;
@@ -164,11 +298,16 @@ public function compressObjectsMethodsName()
164298 $ this ->compress_types ['object_methods ' ] = true ;
165299 }
166300
301+ public function compresWhitespaces ()
302+ {
303+ $ this ->strip_whitespaces = true ;
304+ }
305+
167306
168307 public function setContentByFile ($ file )
169308 {
170309 if (false === file_exists ($ file )) {
171- throw new \Exception ('Not found file ' . $ file );
310+ throw new \Exception ('Not found file ' . $ file );
172311 }
173312 return $ this ->content = file_get_contents ($ file );
174313 }
0 commit comments