187 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
	
	
<?php
 | 
						|
 | 
						|
    namespace WMarkDown\ScriptsAnalyzer;
 | 
						|
 | 
						|
    class PHP extends \WMarkDown\Abstracts\ScriptsAnalyzer{
 | 
						|
 | 
						|
        private static $custom_types = [
 | 
						|
            "__construct" => "constructor",
 | 
						|
            "__destruct" => "destructor",
 | 
						|
            "__call" => "mágico"
 | 
						|
        ];
 | 
						|
 | 
						|
        public function analyze($file, $path = null, &$languages = [], $level = 0){
 | 
						|
 | 
						|
            if(!($content = \WMarkDown\ScriptsAnalyzer::get_content($file, $path)))
 | 
						|
                return;
 | 
						|
 | 
						|
            $namespace = "";
 | 
						|
            $class_name = "";
 | 
						|
            $class_type = "default";
 | 
						|
            $security = [0];
 | 
						|
            $p = [1, 2, 4]; // Cursor position.
 | 
						|
            $data = \WMarkDown::string_variables(file_exists($wmd_path = $this->parent->get_wmd_path($file, $path)) ? file_get_contents($wmd_path) : $this->original_wmd, array_merge([
 | 
						|
                "subkey_words" => preg_match('/^.+' . $this->common["project"] . '\.([^\/]+)\.php\.w\.md$/', $wmd_path) ? preg_replace_callback('/^.+' . $this->common["project"] . '\.([^\/]+)\.php\.w\.md$/', function($values){
 | 
						|
                    return substr(preg_replace('/[,\.]+/', ",", preg_replace_callback('/([A-Z]+)?([A-Z][a-z0-9]+)/', function($subvalues){
 | 
						|
                        return ($subvalues[1] ? "," . $subvalues[1] : "") . "," . strtolower($subvalues[2]);
 | 
						|
                    }, $values[1])), 1);
 | 
						|
                }, $wmd_path) : "main",
 | 
						|
                "path" => substr($wmd_path, $this->root_l + 8),
 | 
						|
                "subpath" => substr($wmd_path, $this->root_l + 8, -5),
 | 
						|
                "file" => preg_replace('/^.+\/([^\/]+)\.w\.md$/', "$1", $wmd_path)
 | 
						|
            ], $this->common));
 | 
						|
            $last_method = null;
 | 
						|
 | 
						|
            !isset($languages["php"]) && ($languages["php"] = []);
 | 
						|
            $languages["php"][$x = count($languages["php"])] = ["path" => $wmd_path, "level" => $level, "methods" => []];
 | 
						|
 | 
						|
            // Limpiamos el Script  de saltos de línea y comentarios y unificamos los espaciados.
 | 
						|
            $content = preg_replace_callback('/("(([^\\\\"]+|\\\\.)*)"|\'(([^\\\\\']+|\\\\.)*)\')|([\t\s]|[\r\n]|\/\/[^\r\n]*|\/\*(([\r\n]+|[^\*]+|\*[^\/])*)\*\/)+/', function($values){
 | 
						|
                return $values[1] ? $values[0] : " ";
 | 
						|
            }, $content);
 | 
						|
 | 
						|
            // Buscamos espacios de nombres, clases, interfaces, abstracciones y métodos.
 | 
						|
            while((true || $security[0] ++ < 100) && preg_match('/\b(' .
 | 
						|
                'namespace ([^; ]+);|' .
 | 
						|
                '(class|interface) ([a-zA-Z0-9_]+)|' .
 | 
						|
                '((public|protected|private) )?(static )?function ([a-zA-Z0-9_]+) ?\('  .
 | 
						|
            ')/', $content, $matches, PREG_OFFSET_CAPTURE)){
 | 
						|
 | 
						|
                $l = count($matches);
 | 
						|
 | 
						|
                $content = substr($content, $matches[0][1] + strlen($matches[0][0]));
 | 
						|
 | 
						|
                if($l > $p[2] + 1){ // Método.
 | 
						|
 | 
						|
                    $method_access = trim($matches[$p[2] + 1][0]);
 | 
						|
                    $method_name = $matches[$p[2] + 4][0];
 | 
						|
                    $languages["php"][$x]["methods"][] = $method_full_name = $class_name . ($matches[$p[2] + 3][0] ? "::" : "->") . $method_name;
 | 
						|
                    $method_type = isset(self::$custom_types[$method_name]) ? self::$custom_types[$method_name] : ($matches[$p[2] + 3][0] ? "static" : "object");
 | 
						|
                    $parameters = [];
 | 
						|
                    $see = [];
 | 
						|
                    $return = null;
 | 
						|
                    $security[1] = 0;
 | 
						|
                    $security[2] = 0;
 | 
						|
 | 
						|
                    if(trim($content)[0] != ")"){ // Verificamos que tiene parámetros.
 | 
						|
 | 
						|
                        $i = 1; // Si llega a 0 es que se cerró el bloque de los parámetros.
 | 
						|
                        $default_value = "";
 | 
						|
                        $parameter_name = null;
 | 
						|
                        $parameter_type = null;
 | 
						|
                        $parameter_reference = false;
 | 
						|
 | 
						|
                        // Analizamos los parámetros.
 | 
						|
                        while((true || $security[1] ++ < 20) && preg_match('/' .
 | 
						|
                            '(((?![\$\&])[a-zA-Z0-9_])+ )?(\&)?\$([a-zA-Z0-9_]+)|' .
 | 
						|
                            ' ?(=) ?(null|true|false|\d+|"(([\\\\"]+|\\\\.)*)"|\'(([\\\\\']+|\\\\.)*)\')?|' .
 | 
						|
                            ' ?(,) ?|' .
 | 
						|
                            '([^,\(\)\[\]\{\}"\']+|"(([\\\\"]+|\\\\.)*)"|\'(([\\\\\']+|\\\\.)*)\')|' .
 | 
						|
                            '([\(\[\{])|([\}\]\)])' .
 | 
						|
                        '/', $content, $submatches, PREG_OFFSET_CAPTURE)){
 | 
						|
 | 
						|
                            $m = count($submatches);
 | 
						|
 | 
						|
                            $content = substr($content, $submatches[0][1] + strlen($submatches[0][0]));
 | 
						|
 | 
						|
                            if($m > 17 && $submatches[17][0]) // Apertura de bloque.
 | 
						|
                                $i ++;
 | 
						|
                            else if($m > 18 && $submatches[18][0]){ // Cierre de bloque.
 | 
						|
                                if(!-- $i){
 | 
						|
                                    $parameters[] = [
 | 
						|
                                        "name" => $parameter_name,
 | 
						|
                                        "type" => $parameter_type,
 | 
						|
                                        "reference" => $parameter_reference,
 | 
						|
                                        "default" => $default_value
 | 
						|
                                    ];
 | 
						|
                                    break;
 | 
						|
                                };
 | 
						|
                            }elseif($m > 11 && $submatches[11][0]){ // Se cierra un parámetro.
 | 
						|
                                if($i > 1)
 | 
						|
                                    $default_value = $default_value . $submatches[0][0];
 | 
						|
                                else{
 | 
						|
                                    $parameters[] = [
 | 
						|
                                        "name" => $parameter_name,
 | 
						|
                                        "type" => $parameter_type,
 | 
						|
                                        "reference" => $parameter_reference,
 | 
						|
                                        "default" => $default_value
 | 
						|
                                    ];
 | 
						|
                                    $default_value = "";
 | 
						|
                                    $parameter_name = null;
 | 
						|
                                    $parameter_type = null;
 | 
						|
                                    $parameter_reference = false;
 | 
						|
                                };
 | 
						|
                            }elseif($submatches[4][0]){ // Se crea un nuevo parámetro.
 | 
						|
                                $parameter_name = ($submatches[3][0] ? "&" : "") . "$" . $submatches[4][0];
 | 
						|
                                $parameter_type = $submatches[1][0] ? $submatches : null;
 | 
						|
                                $parameter_reference = !!$submatches[3][0];
 | 
						|
                            }elseif($m > 6 && $submatches[6][0]) // Valor por defecto.
 | 
						|
                                $default_value = $submatches[6][0];
 | 
						|
 | 
						|
                        };
 | 
						|
                    }else // No tiene párametros de entrada.
 | 
						|
                        $content = substr($content, 1);
 | 
						|
 | 
						|
                    $i = 0;
 | 
						|
                    $body = "";
 | 
						|
 | 
						|
                    // Analizamos bloques de sentencias para analizar inicio y fin del método.
 | 
						|
                    while((true || $security[2] ++ < 40) && preg_match('/[\{\}]/', $content, $submatches, PREG_OFFSET_CAPTURE)){
 | 
						|
 | 
						|
                        $end = false;
 | 
						|
 | 
						|
                        $body .= substr($content, 0, $submatches[0][1]) . $submatches[0][0];
 | 
						|
                        $content = substr($content, $submatches[0][1] + strlen($submatches[0][0]));
 | 
						|
 | 
						|
                        switch($submatches[0][0]){
 | 
						|
                            case "{":
 | 
						|
                                $i ++;
 | 
						|
                            break;
 | 
						|
                            case "}":
 | 
						|
                                $end = !-- $i;
 | 
						|
                            break;
 | 
						|
                        };
 | 
						|
 | 
						|
                        if($end)
 | 
						|
                            break;
 | 
						|
 | 
						|
                    };
 | 
						|
 | 
						|
                    // Analizamos retorno.
 | 
						|
                    $return = preg_match('/\breturn[^;]+[; ]*}$/', $body) ? true : null;
 | 
						|
 | 
						|
                    // Buscamos dependencias de sí mismo.
 | 
						|
                    preg_replace_callback('/"(([^\\\\"]+|\\\\.)*)"|\'(([^\\\\\']+|\\\\.)*)\'|(\$this\->([a-zA-Z0-9_]+|\->)+|\\\\?([a-zA-Z0-9_\\\\]+|\\\\)::[a-zA-Z0-9_]+)\(/', function($values) use(&$see, $class_name){
 | 
						|
                        if(count($values) < 6 || ($values[6] && !preg_match('/\$this\->([^\-\(]+\(|wmarkdown\->)/', $values[0])))
 | 
						|
                            return;
 | 
						|
                        !in_array($method = ($method = preg_replace('/^(\$this(\->)|self(\:{2}))/', $class_name . "$2$3", preg_replace('/^\$this\->wmarkdown/', "\\WMarkDown", substr($values[0], 0, -1))))[0] == '\\' ? substr($method, 1) : $method, $see) && ($see[] = $method);
 | 
						|
                    }, $body);
 | 
						|
 | 
						|
                    // Añadimos el método al código WMD almacenado en $data tras el último método registrado.
 | 
						|
                    $data = $this->parent->add_method($data, $last_method, [
 | 
						|
                        "access" => $method_access,
 | 
						|
                        "language_script" => "PHP",
 | 
						|
                        "name" => $method_full_name,
 | 
						|
                        "type" => $method_type,
 | 
						|
                        "see" => $see,
 | 
						|
                        "parameters" => $parameters,
 | 
						|
                        "return" => $return,
 | 
						|
                        "hash" => md5($content)
 | 
						|
                    ]);
 | 
						|
                    $last_method = $method_full_name;
 | 
						|
 | 
						|
                }elseif($l > $p[1] + 1){ // Clase
 | 
						|
                    $class_type = $matches[$p[1] + 1][0];
 | 
						|
                    $class_name = $namespace . '\\' . $matches[$p[1] + 2][0];
 | 
						|
                }else // Espacio de nombres.
 | 
						|
                    $class_name = $namespace = $matches[$p[0] + 1][0];
 | 
						|
 | 
						|
            };
 | 
						|
 | 
						|
            // Creamos el fichero WMD del fichero PHP.
 | 
						|
            \WMarkDown::save_file($wmd_path, $data);
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
    };
 |