2009-07-24 7 views
82

Sé que include, isset, require, print, echo, y algunos otros no son funciones sino construcciones de lenguaje.¿Cuál es la diferencia entre una construcción de lenguaje y una función "incorporada" en PHP?

Algunos de estos constructos de lenguaje necesitan paréntesis, otros no.

require 'file.php'; 
isset($x); 

Algunos tienen un valor de retorno, otros no.

print 'foo'; //1 
echo 'foo'; //no return value 

Entonces, ¿cuál es la interna diferencia entre una construcción del lenguaje y una función incorporada?

Respuesta

123

(Este es más largo de lo que esperaba, por favor tengan paciencia conmigo)

La mayoría de los lenguajes se componen de algo llamado "sintaxis": el lenguaje se compone de varias palabras clave bien definidas, y la gama completa de expresiones que puede construir en ese lenguaje se construye a partir de esa sintaxis.

Por ejemplo, supongamos que tiene un simple "lenguaje" aritmético de cuatro funciones que solo toma enteros de un solo dígito como entrada e ignora completamente el orden de las operaciones (le dije que era un lenguaje simple). Que el lenguaje puede ser definida por la sintaxis:

// The | means "or" and the := represents definition 
$expression := $number | $expression $operator $expression 
$number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 
$operator := + | - | * | /

A partir de estas tres reglas, se puede construir cualquier número de expresiones aritméticas de los números de entrada única. A continuación, puede escribir un analizador para esta sintaxis que desglosa cualquier entrada válida en sus tipos de componente ($expression, $number o $operator) y trata el resultado. Por ejemplo, la expresión 3 + 4 * 5 se pueden desglosar de la siguiente manera:

// Parentheses used for ease of explanation; they have no true syntactical meaning 
$expression = 3 + 4 * 5 
      = $expression $operator (4 * 5) // Expand into $exp $op $exp 
      = $number $operator $expression // Rewrite: $exp -> $num 
      = $number $operator $expression $operator $expression // Expand again 
      = $number $operator $number $operator $number // Rewrite again

Ahora tenemos una sintaxis completamente analizada, en nuestro idioma definido, por la expresión original. Una vez que tenemos esto, podemos ir y escribir un analizador para encontrar los resultados de todas las combinaciones de $number $operator $number, y escupir un resultado cuando solo tenemos un $number a la izquierda.

Tenga en cuenta que no quedan constructos $expression en la versión analizada final de nuestra expresión original. Eso es porque $expression siempre se puede reducir a una combinación de otras cosas en nuestro idioma.

PHP es muy parecido: las construcciones de lenguaje se reconocen como el equivalente de nuestro $number o $operator. Ellos no se pueden reducir a otras construcciones de lenguaje; en cambio, son las unidades base a partir de las cuales se construye el lenguaje. La diferencia clave entre funciones y construcciones de lenguaje es la siguiente: el analizador trata directamente con construcciones de lenguaje. Simplifica las funciones en construcciones de lenguaje.

La razón por la que las construcciones de lenguaje pueden o no requerir paréntesis y el motivo por el que algunos tienen valores de retorno mientras que otros no dependen completamente de los detalles técnicos específicos de la implementación del analizador de PHP. No estoy tan bien versado en cómo funciona el programa de análisis, así que no puedo responder a estas preguntas específicamente, pero imaginemos por un segundo un lenguaje que comienza con esto:

$expression := ($expression) | ...

Efectivamente, este lenguaje es libre de tomar cualquier expresión que encuentre y deshacerse de los paréntesis que la rodean.PHP (y aquí estoy empleando pura conjetura) puede emplear algo similar para sus construcciones de lenguaje: print("Hello") puede reducirse a print "Hello" antes de ser analizado, o viceversa (las definiciones de lenguaje pueden agregar paréntesis y deshacerse de ellas).

Esta es la raíz de por qué no se puede volver a definir las construcciones del lenguaje como echo o print: están codificados de manera efectiva en el analizador, mientras que las funciones se asignan a un conjunto de construcciones del lenguaje y el analizador le permite cambiar que la cartografía en compilación o en tiempo de ejecución para sustituir su propio conjunto de construcciones de lenguaje o expresiones.

Al final del día, la diferencia interna entre constructos y expresiones es la siguiente: el analizador entiende y trata los constructos del lenguaje. Las funciones incorporadas, aunque proporcionadas por el idioma, se asignan y se simplifican a un conjunto de construcciones de lenguaje antes del análisis.

Más información:

  • Backus-Naur form, la sintaxis utilizada para definir lenguajes formales (yacc utiliza este formulario)

Editar: Lectura a través de algunas de las otras respuestas, las personas hacen buenos puntos . Entre ellos:

  • Un idioma incorporado es más rápido de llamar que una función. Esto es cierto, aunque sea marginalmente, porque el intérprete de PHP no necesita asignar esa función a sus equivalentes incorporados en el lenguaje antes de analizar. En una máquina moderna, sin embargo, la diferencia es bastante insignificante.
  • Un idioma incorporado omite la comprobación de errores. Esto puede o no ser cierto, dependiendo de la implementación interna de PHP para cada uno de ellos. Ciertamente, es cierto que, en la mayoría de los casos, las funciones tendrán una comprobación de errores más avanzada y otras funciones que los integrantes no tienen.
  • Las construcciones de lenguaje no se pueden usar como devoluciones de llamada de funciones. Esto es cierto, porque una construcción es que no es una función. Son entidades separadas. Cuando codifica una función incorporada, no está codificando una función que toma argumentos: la sintaxis de la función incorporada la maneja directamente el analizador, y se reconoce como una función integrada, en lugar de una función. (Esto puede ser más fácil de entender si considera idiomas con funciones de primera clase: efectivamente, puede pasar funciones como objetos. No puede hacer eso con construcciones internas)
+3

¡gracias por esta gran respuesta! –

+2

Gran respuesta que es lo suficientemente abierta como para aplicarse a muchos idiomas, no solo a PHP. ¡Gracias! –

+0

Claro, muy largo, pero ¡guau !, definitivamente vale la pena. –

4

Después de vadear el código, he encontrado que php analiza algunas de las declaraciones en un archivo yacc. Entonces son casos especiales.

(ver Zend/zend_language_parser.y)

Aparte de eso no creo que hay otras diferencias.

1

Puede override built-in functions. Las palabras clave son para siempre

+0

No es una función incorporada. Se define en la extensión APD (Advanced PHP Debugger). –

+0

sobre las funciones principales, puede tener un botín en la extensión runkit (tampoco es un núcleo, es una extensión, por lo que no responde al OP, sino solo a esta respuesta); es realmente poderoso, y más reciente que APD (y creo que escuché hace un tiempo que algunas personas todavía estaban trabajando en él, incluso si no se muestra en pecl.php.net) –

14

Las construcciones de lenguaje son provistas por el lenguaje mismo (como instrucciones como "si", "mientras", ...); de ahí su nombre.

Una consecuencia de esto es que son más rápidos que se invoque que predefinida o funciones definidas por el usuario (o eso he oído/leído varias veces)

no tengo idea de cómo se hace, pero una cosa que pueden hacer (debido a que se integran directamente en el lenguaje) es "eludir" algún tipo de mecanismo de manejo de errores. Por ejemplo, isset() se puede usar con variables no existentes sin causar ningún aviso, advertencia o error.

function test($param) {} 
if (test($a)) { 
    // Notice: Undefined variable: a 
} 

if (isset($b)) { 
    // No notice 
} 

* Tenga en cuenta que no es el caso para las construcciones de todos los idiomas.

Otra diferencia entre funciones y construcciones de lenguaje es que algunas de ellas se pueden llamar sin paréntesis, como una palabra clave.

Por ejemplo:

echo 'test'; // language construct => OK 

function my_function($param) {} 
my_function 'test'; // function => Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING 

También en este caso, no es el caso para todas las construcciones del lenguaje.

Supongo que no hay absolutamente ninguna manera de "deshabilitar" una construcción de lenguaje porque es parte del lenguaje en sí. Por otro lado, muchas funciones PHP "incorporadas" no están realmente integradas porque las proporcionan extensiones que siempre están activas (pero no todas)

Otra diferencia es ese lenguaje construcciones no pueden ser utilizados como "punteros de función" (quiero decir, las devoluciones de llamada, por ejemplo):

$a = array(10, 20); 

function test($param) {echo $param . '<br />';} 
array_map('test', $a); // OK (function) 

array_map('echo', $a); // Warning: array_map() expects parameter 1 to be a valid callback, function 'echo' not found or invalid function name 

que no tienen ninguna otra idea que viene a la mente en este momento ... y no hacer saber mucho sobre los aspectos internos de PHP ...Así que va a ser ahora mismo ^^

Si no consigue mucho respuestas aquí, a lo mejor que se puede pedir esto a la lista de correo internals (ver http://www.php.net/mailing-lists.php), donde hay muchos desarrolladores de PHP-core ; ellos son los que probablemente saber acerca de esas cosas ^^

(y estoy realmente interesado por las otras respuestas, por cierto ^^)

Como referencia: list of keywords and language constructs in PHP

+0

Puede tener una función que acepte un no- establecer la variable sin generar un aviso tomando la variable por referencia. Esto no se limita a construcciones de lenguaje como isset(). –

+0

Oh, no pensé en eso :-(¡Gracias! –

Cuestiones relacionadas