PHP对象定义缓存?删除带有反射的方法时遇到问题

PHP对象定义缓存?删除带有反射的方法时遇到问题,php,reflection,Php,Reflection,我正在处理一个对象,允许我们修改包含PHP对象的PHP文件。(具体来说,它们是我们必须修改的条令实体文件。) 不管怎么说,没有这些令人厌烦的细节,这里就是正在发生的事情。我首先找到类文件的位置,并包含它。然后,我使用下面的代码创建一个类实例和一个类反射器。如您所见,当我实例化对象和反射器时,我还调用一个方法将类的文本从磁盘加载到字符串中,并调用另一个方法将该字符串逐行分解为数组 public function loadClass() if(!class_exists($this->c

我正在处理一个对象,允许我们修改包含PHP对象的PHP文件。(具体来说,它们是我们必须修改的条令实体文件。)

不管怎么说,没有这些令人厌烦的细节,这里就是正在发生的事情。我首先找到类文件的位置,并包含它。然后,我使用下面的代码创建一个类实例和一个类反射器。如您所见,当我实例化对象和反射器时,我还调用一个方法将类的文本从磁盘加载到字符串中,并调用另一个方法将该字符串逐行分解为数组

public function loadClass()
   if(!class_exists($this->class_name)) {
      $this->error = "Class name: '$this->class_name' was not found.";}
   else {
      //Class is found. Load it and populate properties
      $this->oClass          = new $this->class_name;
      $this->oRClass         = new \ReflectionClass($this->oClass);
      $this->source_file     = $this->oRClass->getFileName();
      $this->error           = "";
      $this->class_namespace = $this->oRClass->getNamespaceName();
      $this->getClassText();  //Load class code from source file
      $this->getClassArray(); //Load class text into array
   }
}
然后,我使用一个名为“
deleteMethod()
”的函数删除特定方法的PHP代码,如下所示:
$this->deleteMethod(“badMethod”)。然后,该函数找到所讨论方法的起始行和结束行,删除该行,将类PHP代码保存回磁盘,并再次运行“
loadClass()
”以重新解析更新的对象,以便进行更多编辑。下面是“
deleteMethod()
”函数的摘录

$oMethod = $this->oRClass->getMethod($meth_name);       //Get a refection method object 
$oMethod->setAccessible(true);                          //In case method is private
$start_line = $oMethod->getStartLine() -1;              //Line method starts at
$length = $oMethod->getEndLine() - $start_line + 1      //Number of lines in method
array_splice($this->class_array, $start_line, $length); //Hack lines out of array
$this->class_text = implode("\n", $this->class_array);  //Convert array back to a string
$this->saveClassText();                              //Save updated code back to disk.
$this->loadClass();                                     //Reload and reparse for consistancy
问题是对象可能被缓存在某个地方。当我运行
$this->deleteMethod(“anotherBadMethod”)函数,它不再返回下一个要删除的方法的正确开始/结束行。经过一些检查,很明显,当我试图获取下一个要删除的方法的开始/结束行时,PHP仍然使用旧的类定义。它似乎没有“看到”某些代码已从文件中删除,行号已更改。如您所见,每次运行
loadClass()
时,我都会实例化对象和反射对象。是的,在实例化它们之前,我尝试将它们设置为NULL

我还验证了PHP是否正确地看到了类定义文件。这意味着即使包含了该文件,反射
getFileName()
确实看到类已在其应位于的位置定义


苏呜。。。。PHP缓存是我在内存中包含的类的定义吗?如果是这样的话,我该如何冲销这些现金?有什么方法可以“取消定义”该类并重新加载它吗?任何帮助都将不胜感激。

按照您的说法,这是不可能的PHP只能加载一次类定义。在类定义加载到内存中后,“刷新”它的唯一方法是终止脚本并重新执行它。如果尝试重新包含该文件,显然会出现“类已定义错误”。无论脚本运行多长时间,只要类定义在内存中,就没有什么可以更改的(除非使用第三方扩展)

反射API作用于内存中的类定义,而不是磁盘上的类定义

我认为你有三个选择:

  • 使用磁盘上的类定义。这意味着您不能使用反射,但必须使用标记器/解析器
  • 篡改文件,以便在另一个命名空间中重新加载该类。这将极大地污染您的全局命名空间,因为一旦定义了许多其他一次性使用命名空间,就无法卸载它们
  • 在一个单独的进程中执行加载/修改类的脚本。当进程启动时,它将加载类定义,并在终止时将忘记所有内容,从而产生您想要的“刷新”效果。这显然是你最好的选择
您的
loadClass()
方法将类文件内容加载到数组中,但它不是将类定义加载到PHP解释器中的方法。看起来您对
class\u exists()
的调用正在触发自动加载程序,而这正是将类实际加载到PHP中的原因

据我所知,不可能“重新加载”已加载到脚本中的类定义。尝试这样做会导致脚本崩溃,并出现致命错误

我认为你有两个选择:

  • 编辑并保存类文件后,将脚本重定向到自身,然后退出。这将重新启动脚本并加载新编辑的类版本。重定向时,最初发布到脚本的任何参数都必须进入查询字符串
  • 使用(PECL扩展)从类中删除该方法,而无需重新加载任何内容

  • 唐!我最近也有同样的问题。我最终采用的方法是将类的文本加载到字符串文件中,正如您所做的那样。但是,创建一个“更改缓冲区”来保存您想要进行的所有更改。为此,我使用了一个私有类变量数组。
    我还添加了一个名为$array_extract的函数,它提取指定的数组元素块,并将其作为字符串返回。
    因此,
    deleteMethod()
    实际上并不修改
    $class\u文本
    ,或
    $class\u数组
    变量。但是,它会找到将被删除的文本,并将其推送到数组中供以后处理

    当对象保存回磁盘时,实际上会处理更改,如您在
    saveObject()
    函数中所看到的。此函数只能在处理结束时调用一次。我想把它放进一个析构函数里。
    公共函数saveObject(){
    如果($this->num\u更改){
    $num\u recs=count($this->del\u text\u buffer);
    对于($i=0;$iclass\u text=str\u replace($this->del\u text\u buffer[$i],“”,$this->class\u text,$changes\u);
    }
    $result=文件内容($this->source\u文件,$this->class\u文本);
    $this->num\u changes=0;
    }
    
    }

    我今天也遇到了这个问题,有一段时间我无意中发现了这个问题,直到我发现了这个问题,并认为它不可能。但是,有一个很好的解决方法:只需编辑我需要的函数/方法 private $del_text_buffer = array(); //Array holding text to delete public function loadClass() { if(!class_exists($this->class_name)) { $this->error = "Class name: '$this->class_name' was not found."; } else {//Class is found. Load it and populate properties $this->oClass = new $this->class_name; $this->oRClass = new \ReflectionClass($this->oClass); $this->source_file = $this->oRClass->getFileName(); $this->error = ""; $this->class_namespace = $this->oRClass->getNamespaceName(); $this->class_text = file_get_contents($this->source_file); $this->class_array = explode("\n", $this->class_text); } } private function array_extract($haystack, $start_index, $end_index){ $result = false; if(is_array($haystack)) { $extract = array(); $n = 0; for($i=$start_index; $i<=$end_index; $i++) { $extract[$n] = $haystack[$i]; $n++; } $extract = implode("\n", $extract); $result = $extract; } return $result; } public function deleteMethod($meth_name = "") { $result = false; $oMethod = $this->oRClass->getMethod($meth_name); //Find where method is located, and hack it out $start_index = $oMethod->getStartLine() -1; $end_index = $oMethod->getEndLine() -1; $del_string = $this->array_extract($this->class_array, $start_index, $end_index); array_push($this->del_text_buffer, $del_string); $this->num_changes++; //--- Delete the comment attached to the text, if any $comment_txt = $oMethod->getDocComment(); if($comment_txt != "") { array_push($this->del_text_buffer, $comment_txt); $this->num_changes++; } } public function saveObject() { if($this->num_changes) { $num_recs = count($this->del_text_buffer); for($i=0; $iclass_text = str_replace($this->del_text_buffer[$i], "", $this->class_text, $changes_made); } $result = file_put_contents($this->source_file, $this->class_text); $this->num_changes = 0; } }