187 lines
9.7 KiB
PHP
187 lines
9.7 KiB
PHP
|
<?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);
|
||
|
|
||
|
}
|
||
|
|
||
|
};
|