¿Qué tan eficiente es el substr de PHP?

Estoy escribiendo un analizador sintáctico en PHP que debe poder manejar cadenas grandes en memoria, por lo que este es un problema algo importante. (es decir, por favor no “optimizar prematuramente” llámame, por favor)

¿Cómo funciona la función substr ? ¿Hace una segunda copia de los datos de cadena en la memoria, o hace referencia al original? ¿Debería preocuparme por llamar, por ejemplo, $str = substr($str, 1); en un bucle?

Para avanzar en el comentario de Chad, su código requeriría que ambas cadenas (la completa y la que tiene uno completo menos el primer carácter) estuvieran en la memoria al mismo tiempo (aunque no debido a la tarea asignada por Chad). Ver:

 $string = str_repeat('x', 1048576); printf("MEM: %d\nPEAK: %d\n", memory_get_usage(), memory_get_peak_usage()); substr($string, 1); printf("MEM: %d\nPEAK: %d :-(\n", memory_get_usage(), memory_get_peak_usage()); $string = substr($string, 1); printf("MEM: %d\nPEAK: %d :-(\n", memory_get_usage(), memory_get_peak_usage()); 

Emite algo así como (los valores de memoria están en bytes):

 MEM: 1093256 PEAK: 1093488 MEM: 1093280 PEAK: 2142116 :-( MEM: 1093276 PEAK: 2142116 :-( 

Si realmente está buscando la eficiencia, necesitará mantener un puntero, quiero decir índice , con su cadena. Muchas funciones de cadena aceptan un desplazamiento para comenzar a operar desde (como el tercer parámetro de strpos() ). Normalmente recomendaría escribir un objeto para envolver esta funcionalidad, pero si espera usar mucho eso, podría causar un cuello de botella de rendimiento. Aquí hay un ejemplo de lo que quiero decir (sin OO):

 while ($whatever) { $pos = strpos($string, $myToken, $startIndex); # do something using $pos $startIndex = $pos; } 

Si lo desea, puede escribir su propia clase contenedora que realice estas operaciones de cadena y ver si tiene un impacto de velocidad:

 class _String { private $string; private $startIndex; private $length; public function __construct($string) { $this->string = $string; $this->startIndex = 0; $this->length = strlen($string); } public function substr($from, $length = NULL) { $this->startIndex = $from; if ($length !== NULL) { $this->endIndex = $from + $length; } } # other functions you might use # ... } 

Sí, debe tener cuidado al hacer cualquier manipulación de cadena dentro de un bucle ya que se generarán nuevas copias de la cadena en cada iteración.