1
0
mirror of https://github.com/php/doc-es.git synced 2026-03-25 07:52:21 +01:00
Files
archived-doc-es/language/functions.xml
Pedro Antonio Gil Rodríguez 73375a8f2e Actualización a la última versión
git-svn-id: https://svn.php.net/repository/phpdoc/es/trunk@338335 c90b9560-bf6c-de11-be94-00142212c4b1
2015-12-21 13:57:57 +00:00

1573 lines
41 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 20f201c32ce940b21678860ebe00aad67c0cac96 Maintainer: seros Status: ready -->
<!-- Reviewed: no Maintainer: seros -->
<chapter xml:id="language.functions" xmlns="http://docbook.org/ns/docbook">
<title>Funciones</title>
<sect1 xml:id="functions.user-defined">
<title>Funciones definidas por el usuario</title>
<para>
Una función puede ser definida empleando una sintaxis como la siguiente:
</para>
<para>
<example>
<title>Seudocódigo para demostrar el uso de funciones</title>
<programlisting role="php">
<![CDATA[
<?php
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
{
echo "Función de ejemplo.\n";
return $valor_devuelto;
}
?>
]]>
</programlisting>
</example>
</para>
<simpara>
Cualquier código PHP válido puede aparecer dentro de una función, incluso otras
funciones y definiciones de
<link linkend="keyword.class">clases</link>.
</simpara>
<para>
Los nombres de las funciones siguen las mismas reglas que las demás etiquetas de PHP. Un
nombre de función válido comienza con una letra o guión bajo, seguido de
cualquier número de letras, números o guiones bajos. Como expresión regular
se expresaría así:
<literal>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*</literal>.
</para>
&tip.userlandnaming;
<simpara>
No es necesario definir una función antes de que sea referenciada,
<emphasis>excepto</emphasis> cuando esta esté condicionalmente definida como
se muestra en los dos ejemplos de abajo.
</simpara>
<para>
Cuando una función está definida de una forma condicional como en los dos
ejemplos siguientes, sus definiciones deben ser procesadas <emphasis>antes</emphasis>
de ser llamadas.
</para>
<para>
<example>
<title>Funciones condicionales</title>
<programlisting role="php">
<![CDATA[
<?php
$hacer_algo = true;
/* No podemos llamar a foo() desde aquí
ya que no existe aún,
pero podemos llamar a bar() */
bar();
if ($hacer_algo) {
function foo()
{
echo "No existo hasta que la ejecución del programa llegue hasta mí.\n";
}
}
/* Ahora podemos llamar de forma segura a foo()
ya que $hacer_algo se evaluó como verdadero */
if ($hacer_algo) foo();
function bar()
{
echo "Existo desde el momento inmediato que comenzó el programa.\n";
}
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>Funciones dentro de funciones</title>
<programlisting role="php">
<![CDATA[
<?php
function foo()
{
function bar()
{
echo "No existo hasta que se llame a foo().\n";
}
}
/* No podemos llamar aún a bar()
ya que no existe. */
foo();
/* Ahora podemos llamar a bar(),
el procesamiento de foo()
la ha hecho accesible. */
bar();
?>
]]>
</programlisting>
</example>
</para>
<para>
Todas las funciones y clases de PHP tienen ámbito global. Se pueden
llamar desde fuera de una función incluso si fueron definidas dentro, y viceversa.
</para>
<simpara>
PHP no admite la sobrecarga de funciones, ni es posible
'desdefinir' ni redefinir funciones previamente declaradas.
</simpara>
<note>
<simpara>
Los nombres de las fuciones son insensibles a mayúsculas-minúsculas, aunque es una buena
idea llamar a las funciones tal y como aparecen en sus declaraciones.
</simpara>
</note>
<simpara>
Las funciones admiten un <link linkend="functions.variable-arg-list">número variable de
argumentos</link> y <link linkend="functions.arguments.default">argumentos
predeterminados</link>. Véanse también las referencias
de funciones para
<function>func_num_args</function>,
<function>func_get_arg</function>, y
<function>func_get_args</function> para más información.
</simpara>
<para>
En PHP es posible llamar a funciones recursivas.
<example>
<title>Funciones recursivas</title>
<programlisting role="php">
<![CDATA[
<?php
function recursividad($a)
{
if ($a < 20) {
echo "$a\n";
recursividad($a + 1);
}
}
?>
]]>
</programlisting>
</example>
<note>
<simpara>
Las llamadas a funciones/métodos recursivos con más de 100-200 niveles de recursividad pueden
agotar la pila y ocasionar la finalización del script en curso. Especialmente,
las recurisvidades infinitas están consideradas un error de programación.
</simpara>
</note>
</para>
</sect1>
<sect1 xml:id="functions.arguments">
<title>Argumentos de funciones</title>
<simpara>
Cualquier información puede ser pasada a las funciones mediante la lista de argumentos,
la cual es una lista de expresiones delimitadas por comas. Los argumentos son
evaluados de izquierda a derecha.
</simpara>
<para>
PHP admite el paso de argumentos por valor (lo predeterminado), <link
linkend="functions.arguments.by-reference">el paso por
referencia</link>, y <link
linkend="functions.arguments.default">valores de argumentos
predeterminados</link>. Las <link linkend="functions.variable-arg-list">Listas de argumentos
de longitud variable</link> también están soportadas.
</para>
<para>
<example>
<title>Pasar arrays a funciones</title>
<programlisting role="php">
<![CDATA[
<?php
function tomar_array($entrada)
{
echo "$entrada[0] + $entrada[1] = ".$entrada[0]+$entrada[1];
}
?>
]]>
</programlisting>
</example>
</para>
<sect2 xml:id="functions.arguments.by-reference">
<title>Paso de argumentos por referencia</title>
<simpara>
Por defecto, los argumentos de las funciones son pasados por valor (así, si
el valor del argumento dentro de la función cambia, este no
cambia fuera de la función). Para permitir a una función modificar sus
argumentos, éstos deben pasarse por referencia.
</simpara>
<para>
Para hacer que un argumento a una función sea siempre pasado por referencia hay que anteponer
al nombre del argumento el signo 'et' (&amp;) en la definición de la función:
</para>
<para>
<example>
<title>Paso de parámetros de una función por referencia</title>
<programlisting role="php">
<![CDATA[
<?php
function añadir_algo(&$cadena)
{
$cadena .= 'y algo más.';
}
$cad = 'Esto es una cadena, ';
añadir_algo($cad);
echo $cad; // imprime 'Esto es una cadena, y algo más.'
?>
]]>
</programlisting>
</example>
</para>
</sect2>
<sect2 xml:id="functions.arguments.default">
<title>Valores de argumentos predeterminados</title>
<para>
Una función puede definir valores predeterminados al estilo de C++ para argumentos
escalares como sigue:
</para>
<para>
<example>
<title>Uso de parámetros predeterminados en funciones</title>
<programlisting role="php">
<![CDATA[
<?php
function hacer_café($tipo = "capuchino")
{
return "Hacer una taza de $tipo.\n";
}
echo hacer_café();
echo hacer_café(null);
echo hacer_café("espresso");
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Hacer una taza de capuchino.
Hacer una taza de .
Hacer una taza de espresso.
]]>
</screen>
</example>
</para>
<para>
PHP también permite el uso de <type>array</type>s y del tipo especial &null;
como valores predeterminados, por ejemplo:
</para>
<para>
<example>
<title>Usar tipos no escalares como valores predeterminados</title>
<programlisting role="php">
<![CDATA[
<?php
function hacer_café($tipos = array("capuchino"), $fabricanteCafé = NULL)
{
$aparato = is_null($fabricanteCafé) ? "las manos" : $fabricanteCafé;
return "Hacer una taza de ".join(", ", $tipos)." con $aparato.\n";
}
echo hacer_café();
echo hacer_café(array("capuchino", "lavazza"), "una tetera");
?>
]]>
</programlisting>
</example>
</para>
<simpara>
El valor predeterminado debe ser una expresión constante, no (por
ejemplo) una variable, un miembro de una clase o una llamada a una función.
</simpara>
<para>
Obsérvese que cuando se emplean argumentos predeterminados, cualquiera de ellos debería estar a
la derecha de los argumentos no predeterminados; si no, las cosas
no funcionarán como se esperaba. Considérese el siguiente trozo de código:
</para>
<para>
<example>
<title>Uso incorrecto de argumentos predeterminados en una función</title>
<programlisting role="php">
<![CDATA[
<?php
function hacer_yogur($tipo = "acidófilo", $sabor)
{
return "Hacer un tazón de yogur $tipo de $sabor.\n";
}
echo hacer_yogur("frambuesa"); // no funcionará como se esperaba
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Warning: Missing argument 2 in call to hacer_yogur() in
/usr/local/etc/httpd/htdocs/phptest/functest.html on line 41
Hacer un tazón de yogur frambuesa de .
]]>
</screen>
</example>
</para>
<para>
Ahora, compare el ejemplo de arriba con este:
</para>
<para>
<example>
<title>Uso correcto de argumentos predeterminados en una función</title>
<programlisting role="php">
<![CDATA[
<?php
function hacer_yogur($sabor, $tipo = "acidófilo")
{
return "Hacer un tazón de yogur $tipo de $sabor.\n";
}
echo hacer_yogur("frambuesa"); // funciona como se esperaba
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Hacer un tazón de yogur acidófilo de frambuensa.
]]>
</screen>
</example>
</para>
<note>
<simpara>
A partir de PHP 5, los argumentos pasados por referencia pueden tener un valor predeterminado.
</simpara>
</note>
</sect2>
<sect2 xml:id="functions.arguments.type-declaration">
<title>Declaraciones de tipo</title>
<note>
<para>
La declaración de tipos también se conoce como 'Determinación de tipos' en PHP 5.
</para>
</note>
<para>
Las declaraciones de tipo permiten a las funciones especificar que los parámetros sean de cierto tipo.
Si el valor dado es de un tipo incorrecto,
se generará un error: en PHP 5, este error es un error fatal
recuperable, mientras que PHP 7 lanzará una excepción
<classname>TypeError</classname>.
</para>
<para>
Para especificar una declaración de tipo, debe anteponerse el nombre del tipo al
nombre del parámetro. Se puede hacer que una declaración acepte valores &null; si
el valor predeterminado del parámetro se establece a &null;.
</para>
<sect3 xml:id="functions.arguments.type-declaration.types">
<title>Tipos válidos</title>
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Tipo</entry>
<entry>Descripción</entry>
<entry>Versión de PHP mínima</entry>
</row>
</thead>
<tbody>
<row>
<entry>nombre de clase/interfaz</entry>
<entry>
El parámetro debe ser una &instanceof; del nombre de la clase o interfaz
dada.
</entry>
<entry>PHP 5.0.0</entry>
</row>
<row>
<entry><literal>self</literal></entry>
<entry>
El parámetro debe ser una &instanceof; de la misma clase donde
está definido el método. Esto solamente se puede utilizar en clases
y métodos de instancia.
</entry>
<entry>PHP 5.0.0</entry>
</row>
<row>
<entry><type>array</type></entry>
<entry>
El parámetro debe ser un <type>array</type>.
</entry>
<entry>PHP 5.1.0</entry>
</row>
<row>
<entry><type>callable</type></entry>
<entry>
El parámetro debe ser un <type>callable</type> válido.
</entry>
<entry>PHP 5.4.0</entry>
</row>
<row>
<entry><type>bool</type></entry>
<entry>
El parámetro debe ser un valor de tipo <type>boolean</type>.
</entry>
<entry>PHP 7.0.0</entry>
</row>
<row>
<entry><type>float</type></entry>
<entry>
El parámetro debe ser un número de tipo <type>float</type>.
</entry>
<entry>PHP 7.0.0</entry>
</row>
<row>
<entry><type>int</type></entry>
<entry>
El parámetro debe ser un valor de tipo <type>integer</type>.
</entry>
<entry>PHP 7.0.0</entry>
</row>
<row>
<entry><type>string</type></entry>
<entry>
El parámetro debe ser un <type>string</type>.
</entry>
<entry>PHP 7.0.0</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<warning>
<para>
Los alias de los tipos escalares anteriores no están admitidos. En su lugar, son
tratados como nombres de clases o de interfaces. Por ejemplo, el empleo de
<literal>boolean</literal> como parámetro o como tipo devuelto requerirá
un argumento o un valor devuelto que sea unaan &instanceof; de la clase o
interfaz <literal>boolean</literal>, más que el tipo
<type>bool</type>:
</para>
<para>
<example>
<programlisting role="php">
<![CDATA[
<?php
function prueba(boolean $param) {}
prueba(true);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Fatal error: Uncaught TypeError: Argument 1 passed to test() must be an instance of boolean, boolean given, called in - on line 1 and defined in -:1
]]>
</screen>
</example>
</para>
</warning>
</sect3>
<sect3 xml:id="functions.arguments.type-declaration.examples">
&reftitle.examples;
<example>
<title>Declaración básica de tipo clase</title>
<programlisting role="php">
<![CDATA[
<?php
class C {}
class D extends C {}
// Esta no extiende a C.
class E {}
function f(C $c) {
echo get_class($c)."\n";
}
f(new C);
f(new D);
f(new E);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
C
D
Fatal error: Uncaught TypeError: Argument 1 passed to f() must be an instance of C, instance of E given, called in - on line 14 and defined in -:8
Stack trace:
#0 -(14): f(Object(E))
#1 {main}
thrown in - on line 8
]]>
</screen>
</example>
<example>
<title>Declaración básica de tipo interfaz</title>
<programlisting role="php">
<![CDATA[
<?php
interface I { public function f(); }
class C implements I { public function f() {} }
// Esta no implementa I.
class E {}
function f(I $i) {
echo get_class($i)."\n";
}
f(new C);
f(new E);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
C
Fatal error: Uncaught TypeError: Argument 1 passed to f() must implement interface I, instance of E given, called in - on line 13 and defined in -:8
Stack trace:
#0 -(13): f(Object(E))
#1 {main}
thrown in - on line 8
]]>
</screen>
</example>
<example>
<title>Declaración de tipo null</title>
<programlisting role="php">
<![CDATA[
<?php
class C {}
function f(C $c = null) {
var_dump($c);
}
f(new C);
f(null);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
object(C)#1 (0) {
}
NULL
]]>
</screen>
</example>
</sect3>
<sect3 xml:id="functions.arguments.type-declaration.strict">
<title>Tipificación estricta</title>
<para>
Por defecto, PHP fuerza a los valores de un tipo erróneo a ser del tipo
escalar esperado si es posible. Por ejemplo, una función a la que se le pasa un
<type>integer</type> para un parámetro que se prevé sea un <type>string</type>
obtendrá una variable de tipo <type>string</type>.
</para>
<para>
Es posible habilitar el modo escricto en función de cada fichero. El el modo
estricto solamente será aceptada una variable del tipo exacto de la declaración
de tipo, o será lanzada una <classname>TypeError</classname>. La
única excepción a esta regla es que se podría proporcionar un <type>integer</type>
a una función que espere un <type>float</type>.
</para>
<para>
Para habilitar el modo escricto se emplea la sentencia &declare; con la
declaración <literal>strict_types</literal>:
</para>
<caution>
<para>
Habilitar el modo esctricto también afectará a las
<link linkend="functions.returning-values.type-declaration">declaraciones de tipo de devolución</link>.
</para>
</caution>
<note>
<para>
La tipificación estricta se aplica a las llamadas a funciones hechas desde
<emphasis>dentro</emphasis> del fichero con la tipificación estricta habilitada, no a
las funciones declaradas dentro del fichero. Si un fichero sin la tipificación estricta
habilitada realiza una llamada a una función definida en un fichero
con tipificación estricta, será respetada la preferencia del llamador
(tipificación débil), y se forzará el valor.
</para>
</note>
<note>
<para>
La tipificación estricta solamente se define para declaraciones de tipos escalares, y como
tal, requiere PHP 7.0.0 o posterior, ya que las declaraciones de tipo escalar fueron
añadidas en esta versión.
</para>
</note>
<example>
<title>Tipificación estricta</title>
<programlisting role="php">
<![CDATA[
<?php
declare(strict_types=1);
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
int(3)
Fatal error: Uncaught TypeError: Argument 1 passed to sum() must be of the type integer, float given, called in - on line 9 and defined in -:4
Stack trace:
#0 -(9): sum(1.5, 2.5)
#1 {main}
thrown in - on line 4
]]>
</screen>
</example>
<example>
<title>Tipificación débil</title>
<programlisting role="php">
<![CDATA[
<?php
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
// Estos números serán forzados a ser enteros: ¡observe la salida de abajo!
var_dump(sum(1.5, 2.5));
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
int(3)
int(3)
]]>
</screen>
</example>
<example>
<title>Capturar la excepción <classname>TypeError</classname></title>
<programlisting role="php">
<![CDATA[
<?php
declare(strict_types=1);
function sum(int $a, int $b) {
return $a + $b;
}
try {
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
} catch (TypeError $e) {
echo 'Error: '.$e->getMessage();
}
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
int(3)
Error: Argument 1 passed to sum() must be of the type integer, float given, called in - on line 10
]]>
</screen>
</example>
</sect3>
</sect2>
<sect2 xml:id="functions.variable-arg-list">
<title>Listas de argumentos de longitud variable</title>
<simpara>
PHP tiene soporte para listas de argumentos de longitud variable en
funciones definidas por el usuario. Esto se implementa utilizando el
token <literal>...</literal> en PHP 5.6 y posteriores, y utilizando las funciones
<function>func_num_args</function>,
<function>func_get_arg</function>, y
<function>func_get_args</function> en PHP 5.5 y anteriores.
</simpara>
<sect3 xml:id="functions.variable-arg-list.new">
<title><literal>...</literal> en PHP 5.6+</title>
<para>
En PHP 5.6 y posteriores, las listas de argumentos pueden incluir el
token <literal>...</literal> para denotar que la función acepta un
número variable de argumentos. Los argumentos serán pasados a la
variable dada como un aryay, por ejemplo:
<example>
<title>Usando <literal>...</literal> para acceder a argumentos variables</title>
<programlisting role="php">
<![CDATA[
<?php
function sum(...$números) {
$acc = 0;
foreach ($números as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
10
]]>
</screen>
</example>
</para>
<para>
También se puede emplear <literal>...</literal> al llamar a funciones para convertir
un <type>array</type> o variable <classname>Traversable</classname> o
literal en una lista de argumentos:
<example>
<title>Usar <literal>...</literal> para proporcionar argumentos</title>
<programlisting role="php">
<![CDATA[
<?php
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2])."\n";
$a = [1, 2];
echo add(...$a);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
3
3
]]>
</screen>
</example>
</para>
<para>
Se puede especifcar argumentos posicionales normales antes del
token <literal>...</literal>. En este caso, solamente los argumentos al final
que no coincidan con un argumento posicional serán añadidos al array
generado por <literal>...</literal>.
</para>
<para>
También es posible añadir una
<link linkend="language.oop5.typehinting">declraración de tipo</link> antes del
símbolo <literal>...</literal>. Si está presente, todos los argumentos
capturados por <literal>...</literal> deben ser objetos de la clase implicada.
<example>
<title>Argumentos variables de declaración de tipo</title>
<programlisting role="php">
<![CDATA[
<?php
function total_intervals($unit, DateInterval ...$intervals) {
$time = 0;
foreach ($intervals as $interval) {
$time += $interval->$unit;
}
return $time;
}
$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';
// Esto fallará, debido a que null no es un objeto de DateInterval.
echo total_intervals('d', null);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
3 days
Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval, null given, called in - on line 14 and defined in - on line 2
]]>
</screen>
</example>
</para>
<para>
Por último, también es pueden pasar argumentos variables
<link linkend="functions.arguments.by-reference">por referencia</link>
prefijando <literal>...</literal> con el signo
(<literal>&amp;</literal>).
</para>
</sect3>
<sect3 xml:id="functions.variable-arg-list.old">
<title>Versiones antiguas de PHP</title>
<para>
No se requiere una sintaxis especial para señalar que una función es varíadica;
sin embargo, para acceder a los argumentos de la función se debe usar
<function>func_num_args</function>, <function>func_get_arg</function>
y <function>func_get_args</function>.
</para>
<para>
El primer ejemplo de antes se implementaría en PHP 5.5 y anteriores
como sigue:
<example>
<title>Acceder a argumentos variables en PHP 5.5 y anteriores</title>
<programlisting role="php">
<![CDATA[
<?php
function sum() {
$acc = 0;
foreach (func_get_args() as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
10
]]>
</screen>
</example>
</para>
</sect3>
</sect2>
</sect1>
<sect1 xml:id="functions.returning-values">
<title>Devolver valores</title>
<para>
Los valores son devueltos usando la sentencia opcional return. Se
puede devolver cualquier tipo, incluidos arrays y objetos. Esto causa que la
función finalice su ejecución inmediatamente y pase el control de nuevo a
la línea desde la que fue llamada. Véase <function>return</function>
para más información.
</para>
<note>
<para>
Si se omite <function>return</function>, el valor devuelto será
&null;.
</para>
</note>
<sect2>
<title>Empleo de return</title>
<para>
<example>
<title>Empleo de <function>return</function></title>
<programlisting role="php">
<![CDATA[
<?php
function cuadrado($núm)
{
return $núm * $núm;
}
echo cuadrado(4); // imprime '16'.
?>
]]>
</programlisting>
</example>
</para>
<para>
Una función no puede devolver múltiples valores, pero se pueden obtener resultados
similares devolviendo un array.
</para>
<para>
<example>
<title>Devolver un array para obtener múltiples valores</title>
<programlisting role="php">
<![CDATA[
<?php
function números_pequeños()
{
return array (0, 1, 2);
}
list ($cero, $uno, $dos) = números_pequeños();
?>
]]>
</programlisting>
</example>
</para>
<para>
Para devolver una referencia desde una función use el operador de referencia &amp;, en
la declaración de la función y cuando se asigne el valor devuelto a una
variable:
</para>
<para>
<example>
<title>Devolver una referencia desde una función</title>
<programlisting role="php">
<![CDATA[
<?php
function &devolver_referencia()
{
return $algunaref;
}
$nuevaref =& devolver_referencia();
?>
]]>
</programlisting>
</example>
</para>
<simpara>
Para más información sobre referencias, por favor, lea las <link
linkend="language.references">Referencias explicadas</link>.
</simpara>
</sect2>
<sect2 xml:id="functions.returning-values.type-declaration">
<title>Declaraciones de tipo de devolución</title>
<para>
PHP 7 añade soporte para las declaraciones de tipo de devolución. De forma similar a las
<link linkend="functions.arguments.type-declaration">declaraciones de tipo de argumento</link>,
las declaraciones de tipo de devolución especifican el tipo del valor que serán
devuelto desde una función. Están disponibles los mismos
<link linkend="functions.arguments.type-declaration.types">tipos</link>
para las declaraciones de tipo de devolución que para las declaraciones
de tipo de argumento.
</para>
<para>
La <link linkend="functions.arguments.type-declaration.strict">tipificación estricta</link>
también tiene efecto sobre las declaraciones de tipo de devolución. En el modo predeterminado de tipificacón débil,
los valores devueltos serán forzados al tipo correcto si no son ya
de ese tipo. En el modo fuerte, el valor devuelto debe ser del
tipo correcto, o de lo contrario se lanzará una excepción <classname>TypeError</classname>.
</para>
<note>
<para>
Al sobrescribir un método padre, el método hijo debe hacer coincidir cualquier
declaración de tipo de devolución del padre. Si el padre no define un tipo de
devolución, el método hijo puede hacerlo.
</para>
</note>
<sect3 xml:id="functions.returning-values.type-declaration.examples">
&reftitle.examples;
<example>
<title>Declaración básica de tipo de devolución</title>
<programlisting role="php">
<![CDATA[
<?php
function sum($a, $b): float {
return $a + $b;
}
// Observe que será devuelto un float.
var_dump(sum(1, 2));
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
float(3)
]]>
</screen>
</example>
<example>
<title>El modo estricto en acción</title>
<programlisting role="php">
<![CDATA[
<?php
declare(strict_types=1);
function sum($a, $b): int {
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1, 2.5));
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
int(3)
Fatal error: Uncaught TypeError: Return value of sum() must be of the type integer, float returned in - on line 5 in -:5
Stack trace:
#0 -(9): sum(1, 2.5)
#1 {main}
thrown in - on line 5
]]>
</screen>
</example>
<example>
<title>Devolver un objeto</title>
<programlisting role="php">
<![CDATA[
<?php
class C {}
function getC(): C {
return new C;
}
var_dump(getC());
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
object(C)#1 (0) {
}
]]>
</screen>
</example>
</sect3>
</sect2>
</sect1>
<sect1 xml:id="functions.variable-functions">
<title>Funciones variables</title>
<para>
PHP admite el concepto de funciones variables. Esto significa que si
un nombre de variable tiene paréntesis anexos a él, PHP buscará
una función con el mismo nombre que lo evaluado por la variable,
e intentará ejecutarla. Entre otras cosas, esto se puede
usar para implementar llamadas de retorno, tablas de funciones, y así sucesivamente.
</para>
<para>
Las funciones variables no funcionarán con constructores de lenguaje como
<function>echo</function>, <function>print</function>,
<function>unset</function>, <function>isset</function>,
<function>empty</function>, <function>include</function>,
<function>require</function> y similares. Utilice funciones de envoltura para hacer
uso de cualquiera de estos constructores como funciones variables.
</para>
<para>
<example>
<title>Ejemplo de función variable</title>
<programlisting role="php">
<![CDATA[
<?php
function foo() {
echo "En foo()<br />\n";
}
function bar($arg = '')
{
echo "En bar(); el argumento era '$arg'.<br />\n";
}
// Esta es una función de envoltura alrededor de echo
function hacerecho($cadena)
{
echo $cadena;
}
$func = 'foo';
$func(); // Esto llama a foo()
$func = 'bar';
$func('prueba'); // Esto llama a bar()
$func = 'hacerecho';
$func('prueba'); // Esto llama a hacerecho()
?>
]]>
</programlisting>
</example>
</para>
<para>
Los métodos de objetos también puede ser llamados con la sintaxis de funciones variables.
<example>
<title>Ejemplo de método variable</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
function Variable()
{
$nombre = 'Bar';
$this->$nombre(); // Esto llama al método Bar()
}
function Bar()
{
echo "Esto es Bar";
}
}
$foo = new Foo();
$nombrefunc = "Variable";
$foo->$nombrefunc(); // Esto llama a $foo->Variable()
?>
]]>
</programlisting>
</example>
</para>
<para>
Cuando se llaman a métodos estáticos, la llamada a la función es más fuerte que el operador de
propiedad static:
<example>
<title>Ejemplo de método variable con propiedades estáticas</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
static $variable = 'propiedad estática';
static function Variable()
{
echo 'Método Variable llamado';
}
}
echo Foo::$variable; // Esto imprime 'propiedad estática'. No necesita una $variable en este ámbito.
$variable = "Variable";
Foo::$variable(); // Esto llama a $foo->Variable() leyendo $variable en este ámbito.
?>
]]>
</programlisting>
</example>
</para>
<para>
A partir de PHP 5.4.0, se puede llamar a cualquier <type>callable</type> almacenado en una variable.
<example>
<title>Llamables complejos</title>
<programlisting role="php">
<![CDATA[
class Foo
{
static function bar()
{
echo "bar\n";
}
function baz()
{
echo "baz\n";
}
}
$func = array("Foo", "bar");
$func(); // imprime "bar"
$f = array(new Foo, "baz");
$func(); // imprime "baz"
$f = "Foo::bar";
$func(); // imprime "bar" a partrid de PHP 7.0.0; antes, emitía un error fatal
]]>
</programlisting>
</example>
</para>
<para>
Véase también <function>is_callable</function>, <function>call_user_func</function>,
<link linkend="language.variables.variable">
variables variables</link> y <function>function_exists</function>.
</para>
<sect2 role="changelog">
&reftitle.changelog;
<para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>&Version;</entry>
<entry>&Description;</entry>
</row>
</thead>
<tbody>
<row>
<entry>7.0.0</entry>
<entry>
'NombreDeClase::NombreDeMétodo' se permite como función variable.
</entry>
</row>
<row>
<entry>5.4.0</entry>
<entry>
Los arrays, que son llamables válidos, están permitidos como funciones variables.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</sect2>
</sect1>
<sect1 xml:id="functions.internal">
<title>Funciones internas (incluidas)</title>
<para>
PHP se estandariza con muchas funciones y construcciones. También existen
funciones que necesitan extensiones específicas de PHP compiladas, si no,
aparecerán errores fatales "undefined function" ("función no definida"). Por ejemplo,
para usar las funciones de <link linkend="ref.image">image</link> tales como
<function>imagecreatetruecolor</function>, PHP debe ser compilado con
soporte para <productname>GD</productname>. O para usar
<function>mysql_connect</function>, PHP debe ser compilado con
soporte para <link linkend="ref.mysql">MySQL</link>. Hay muchas funciones de núcleo
que está incluidas en cada versión de PHP, tales como las
funciones de <link linkend="ref.strings">string</link> y de
<link linkend="ref.var">variable</link>. Una llamada
a <function>phpinfo</function> o
<function>get_loaded_extensions</function> mostrará las extensiones que están
cargadas en PHP. Observe también que muchas extensiones están habilitadas por defecto y
que el manual de PHP está dividido por extensiones. Véase
<link linkend="configuration">configuración</link>,
<link linkend="install">instalación</link>, y capítulos individuales
de extensiones para más información sobre cómo configurar PHP.
</para>
<para>
Interpretar y comprender un prototipo de una función está explicado dentro de
la sección del manual titulada <link linkend="about.prototypes">cómo interpretar
la definición de una función</link>. Es importante comprender lo que devuelve una
función o si una función funciona directamente con un valor pasado. Por ejemplo,
<function>str_replace</function> devolverá la cadena modificada mientras que
<function>usort</function> funciona con la variable actual pasada.
Cada página del manual también tiene información específica para cada
función, como información sobre parámetros de funciones, cambios de comportamiento,
valores devueltos en caso de éxito o fallo, e información de disponibilidad.
Conocer estas importantes diferencias (a menudo imperceptibles) es crucial para
escribir código de PHP correcto.
</para>
<note>
<simpara>
Si los parámetros dados a una función no son los que se esperaban, como
pasar un <type>array</type> donde se esperaba un <type>string</type>,
el valor devuelto de la función será indefinido. En este caso lo más probable
es que devuelva &null; pero esto es sólo una convención, y no se puede confiar
en ello.
</simpara>
</note>
<para>
Véase también <function>function_exists</function>,
<link linkend="funcref">la referencia de funciones</link>,
<function>get_extension_funcs</function>, y
<function>dl</function>.
</para>
</sect1>
<sect1 xml:id="functions.anonymous">
<title>Funciones anónimas</title>
<simpara>
Las funciones anónimas, también conocidas como <literal>clausuras</literal> (closures), permiten
la creación de funciones que no tienen un nombre especificado. Son más útiles como
valor de los parámetros de <link linkend="language.types.callback">llamadas de retorno</link>,
pero tienen muchos otros usos.
</simpara>
<example>
<title>Ejemplo de función anónima</title>
<programlisting role="php">
<![CDATA[
<?php
echo preg_replace_callback('~-([a-z])~', function ($coincidencia) {
return strtoupper($coincidencia[1]);
}, 'hola-mundo');
// imprime holaMundo
?>
]]>
</programlisting>
</example>
<simpara>
Las clausuras también se pueden usar como valores de variables; PHP automáticamente
convierte tales expresiones en instancias de la
clase interna <classname>Closure</classname>. Se asume que una clausura a una
variable usa la misma sintaxis que cualquier otra asignación, incluido el
punto y coma final:
</simpara>
<example>
<title>Ejemplo de asignación de variable de una función anónima</title>
<programlisting role="php">
<![CDATA[
<?php
$saludo = function($nombre)
{
printf("Hola %s\r\n", $nombre);
};
$saludo('Mundo');
$saludo('PHP');
?>
]]>
</programlisting>
</example>
<simpara>
Las clausuras también pueden heredar variables del ámbito padre. Cualquier
variable de estas debe ser pasado al constructor del lenguaje <literal>use</literal>.
</simpara>
<example>
<title>Heredar variables de un ámbito padre</title>
<programlisting role="php">
<![CDATA[
<?php
$mensaje = 'hola';
// Sin "use"
$ejemplo = function () {
var_dump($mensaje);
};
$ejemplo();
// Heredar $mensaje
$ejemplo = function () use ($mensaje) {
var_dump($mensaje);
};
$ejemplo();
// El valor de la variable heredada está cuando la función
// está definida, no cuando se le invoca
$mensaje = 'mundo';
$ejemplo();
// Reiniciar el mensaje
$mensaje = 'hola';
// Heredar por referencia
$ejemplo = function () use (&$mensaje) {
var_dump($mensaje);
};
$ejemplo();
// El valor cambiado en el ámbito padre
// se refleja dentro de la llamada a la función
$mensaje = 'mundo';
$ejemplo();
// Las clausuras también aceptan argumentos normales
$ejemplo = function ($arg) use ($mensaje) {
var_dump($arg . ' ' . $mensaje);
};
$ejemplo("hola");
?>
]]>
</programlisting>
&example.outputs.similar;
<screen>
<![CDATA[
Notice: Undefined variable: message in /example.php on line 6
NULL
string(4) "hola"
string(4) "hola"
string(4) "hola"
string(5) "mundo"
string(10) "hola mundo"
]]>
</screen>
</example>
<simpara>
Heredar variables del ámbito padre <emphasis>no</emphasis>
es lo mismo que usar variables globales.
Las variables globales existen en el ámbito global, lo que implica que no
importa qué función se esté ejecutando. El ámbito padre de una clausura es la
función en la que la clausura fue declarado (no necesariamente la función
desde la que se llamó). Vea el siguiente ejemplo:
</simpara>
<example>
<title>Clausuras y ámbito</title>
<programlisting role="php">
<![CDATA[
<?php
// Un carro de compras básico que contiene una lista de productos añadidos
// y la cantidad de cada producto. Incluye un método que
// calcula el precio total de los artículos del carro usando una
// clausura como llamada de retorno.
class Carro
{
const PRECIO_MANTEQUILLA = 1.00;
const PRECIO_LECHE = 3.00;
const PRECIO_HUEVOS = 6.95;
protected $productos = array();
public function añadir($producto, $cantidad)
{
$this->productos[$producto] = $cantidad;
}
public function obtenerCantidad($producto)
{
return isset($this->productos[$producto]) ? $this->productos[$producto] :
FALSE;
}
public function obtenerTotal($impuesto)
{
$total = 0.00;
$llamadaDeRetorno =
function ($cantidad, $producto) use ($impuesto, &$total)
{
$precioUnidad = constant(__CLASS__ . "::PRECIO_" .
strtoupper($producto));
$total += ($precioUnidad * $cantidad) * ($impuesto + 1.0);
};
array_walk($this->productos, $llamadaDeRetorno);
return round($total, 2);
}
}
$mi_carro = new Carro;
// Añadir algunos artículos al carro
$mi_carro->añadir('mantequilla', 1);
$mi_carro->añadir('leche', 3);
$mi_carro->añadir('huevos', 6);
// Imprimir el total con un impuesto de venta del 5%.
print $mi_carro->obtenerTotal(0.05) . "\n";
// El resultado es 54.29
?>
]]>
</programlisting>
</example>
<simpara>
Las funciones anónimas son implementadas usando la clase <link linkend="class.closure">
<classname>Closure</classname></link>.
</simpara>
<sect2 role="changelog">
&reftitle.changelog;
<para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>&Version;</entry>
<entry>&Description;</entry>
</row>
</thead>
<tbody>
<row>
<entry>5.4.0</entry>
<entry>
<varname>$this</varname> puede ser usado en funciones anónimas.
</entry>
</row>
<row>
<entry>5.3.0</entry>
<entry>
Las funciones anónimas se encuentran disponibles.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</sect2>
<sect2 role="notes">
&reftitle.notes;
<note>
<simpara>
Es posible usar <function>func_num_args</function>,
<function>func_get_arg</function>, y <function>func_get_args</function>
desde dentro de una clausura.
</simpara>
</note>
</sect2>
</sect1>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->