Incluir constante en cadena sin concatenar

166

¿Hay alguna manera en PHP de incluir una constante en una cadena sin concatenar?

define('MY_CONSTANT', 42);

echo "This is my constant: MY_CONSTANT";
Brian
fuente
12
La intuición me dice que "Esta es mi constante: {MY_CONSTANT}" debería funcionar. No lo hace. Solo pongo esto aquí en caso de que alguien piense lo mismo que yo.
Mikael Lindqvist

Respuestas:

148

No.

Con Strings, PHP no puede distinguir los datos de cadena aparte de los identificadores constantes. Esto se aplica a cualquiera de los formatos de cadena en PHP, incluido heredoc.

constant() es una forma alternativa de obtener una constante, pero tampoco se puede poner una llamada de función en una cadena sin concatenación.

Manual de constantes en PHP

Pekka
fuente
1
+1 de todos modos, ya que sin duda es la respuesta correcta. Primero quería escribir lo mismo que tú, pero después de leer el tuyo, pensé que tenía que presentar algo diferente;)
Felix Kling
3
Jeje! Pero un merecido +1 para todos por creatividad. :)
Pekka
59
"la llamada de función no se puede poner en una cadena" sí, puede:define('ANIMAL','turtles'); $constant='constant'; echo "I like {$constant('ANIMAL')}";
raveren
1
@Raveren, mientras que otros ofrecen variaciones indirectas, creando funciones innecesariamente, la suya es la solución más corta y precisa que se basa en funciones variables, funciones infravaloradas y muy poco utilizadas de PHP. De todo este hilo fui con SU solución particular. Desearía poder +1 más de una vez.
hndcrftd
44
Solo señalé que es posible, no comenté cuál es la mejor manera.
raveren
111

Sí lo es (de alguna manera;)):

define('FOO', 'bar');

$test_string = sprintf('This is a %s test string', FOO);

Probablemente esto no sea lo que buscabas, pero creo que, técnicamente, esto no es concatenación sino una sustitución y, desde este supuesto, incluye una constante en una cadena sin concatenación .

Felix Kling
fuente
55
@Pekka: Lo sé :-D (solo esta vez ...;))
Felix Kling
1
:) El enfoque de @ juraj.blahunka es aún más astuto. Responde la pregunta por carta, pero no su espíritu. :)
Pekka
2
@blahunka: bonito lema. Probablemente lo usemos a diario
Alfabravo
57

Para usar constantes dentro de cadenas, puede usar el siguiente método:

define( 'ANIMAL', 'turtles' ); 
$constant = 'constant';

echo "I like {$constant('ANIMAL')}";


¿Como funciona esto?

Puede usar cualquier nombre de función de cadena y parámetros arbitrarios

Se puede colocar cualquier nombre de función en una variable y llamarlo con parámetros dentro de una cadena entre comillas dobles. Funciona con múltiples parámetros también.

$fn = 'substr';

echo "I like {$fn('turtles!', 0, -1)}";

Produce

me gustan las tortugas

Funciones anónimas también

También puede usar funciones anónimas siempre que ejecute PHP 5.3+.

$escape   = function ( $string ) {
    return htmlspecialchars( (string) $string, ENT_QUOTES, 'utf-8' );
};
$userText = "<script>alert('xss')</script>";
echo( "You entered {$escape( $userText )}" );

Produce html correctamente escapado como se esperaba.

Matrices de devolución de llamada no permitidas!

Si ahora tiene la impresión de que el nombre de la función puede ser invocable, ese no es el caso, ya que una matriz que devuelve verdadero cuando se pasa a is_callablecausaría un error fatal cuando se usa dentro de una cadena:

class Arr
{

    public static function get( $array, $key, $default = null )
    {
        return is_array( $array ) && array_key_exists( $key, $array ) 
            ? $array[$key] 
            : $default;
    }
}

$fn = array( 'Arr', 'get' );
var_dump( is_callable( $fn ) ); // outputs TRUE

// following line throws Fatal error "Function name must be a string"
echo( "asd {$fn( array( 1 ), 0 )}" ); 

Tenga en cuenta

Esta práctica es desaconsejada, pero a veces da como resultado un código mucho más legible, por lo que depende de usted; la posibilidad está ahí.

raveren
fuente
1
Este es un gran truco! Al igual que las otras respuestas, no es realmente una gran victoria sobre la concatenación en términos de esfuerzo y legibilidad, pero es bueno saberlo. Es aún más sexy cuando haces algo así $_ = create_function('$a','return $a;'); $s = "I like {$_(ANIMAL)}". La versión de Thetaiko elimina la necesidad de citas, y un guión bajo es lindo.
Beejor
2
Pude ver que esto es útil para construir un motor de plantillas, pero parece demasiado astuto para usarlo.
Mnebuerquo
21
define( 'FOO', 'bar');  
$FOO = FOO;  
$string = "I am too lazy to concatenate $FOO in my string";
Macswork
fuente
44
Este es el que más uso, cuando tengo un montón de cadenas SQL locas para componer. También ... pasivo-agresivo mucho? ;-)
Beejor
2
Este tiene la menor cantidad de magia, a expensas de verse redundante
BrDaHa
Gran solución Simple y rapido.
Roger Hill
14
define('FOO', 'bar');
$constants = create_function('$a', 'return $a;');
echo "Hello, my name is {$constants(FOO)}";
thetaiko
fuente
13

Si realmente quieres hacer eco constante sin concatenación, aquí hay una solución:

define('MY_CONST', 300);
echo 'here: ', MY_CONST, ' is a number';

nota : en este ejemplo echo toma una serie de parámetros ( mira las comas ), por lo que no es una concatenación real

Echo se comporta como una función, toma más parámetros, es más eficiente que la concatenación, ya que no tiene que concatenar y luego hacer eco, solo hace eco de todo sin la necesidad de crear un nuevo objeto concatenado String :))

EDITAR

Además, si considera concatenar cadenas, pasar cadenas como parámetros o escribir cadenas completas con " , The , (versión de coma) siempre es más rápido, el siguiente va . (Concatenación con ' comillas simples) y el método de construcción de cadenas más lento es usar comillas dobles " , porque las expresiones escritas de esta manera tienen que ser evaluadas contra variables y funciones declaradas.

Juraj Blahunka
fuente
11

Podrías hacerlo:

define( 'FOO', 'bar' );

$constants = get_defined_constants(true); // the true argument categorizes the constants
$constants = $constants[ 'user' ]; // this gets only user-defined constants

echo "Hello, my name is {$constants['FOO']}";
Simón
fuente
6

La forma más fácil es

define('MY_CONSTANT', 42);

$my_constant = MY_CONSTANT;
echo "This is my constant: $my_constant";

Otra forma de usar (s)printf

define('MY_CONSTANT', 42);

// Note that %d is for numeric values. Use %s when constant is a string    
printf('This is my constant: %d', MY_CONSTANT);

// Or if you want to use the string.

$my_string = sprintf('This is my constant: %d', MY_CONSTANT);
echo $my_string;
Jekis
fuente
Considero esto como una buena solución. En algunos casos, la cadena de conexión no funcionará si usa CONSTANTE directo en el interior.
kta
5

Como otros han señalado, no puedes hacer eso. PHP tiene una función constant()que no se puede llamar directamente en una cadena, pero podemos solucionarlo fácilmente.

$constant = function($cons){
   return constant($cons);
};

y un ejemplo básico sobre su uso:

define('FOO', 'Hello World!');
echo "The string says {$constant('FOO')}"; 
Yamiko
fuente
Puede hacerlo en $constant = 'constant';lugar de definir otra función, y funcionaría de manera idéntica ya que esa función ya existe.
redreinard 01 de
2

Aquí hay algunas alternativas a las otras respuestas, que parecen centrarse principalmente en el truco "{$}". Aunque no se hacen garantías sobre su velocidad; Todo esto es azúcar sintáctica pura. Para estos ejemplos, asumiremos que se definió el conjunto de constantes a continuación.

define( 'BREAD', 'bread' ); define( 'EGGS', 'eggs' ); define( 'MILK', 'milk' );

Usando extract ()
Este es bueno porque el resultado es idéntico a las variables. Primero crea una función reutilizable:

function constants(){ return array_change_key_case( get_defined_constants( true )[ 'user' ] ); }

Luego llámalo desde cualquier ámbito:

extract( constants() );
$s = "I need to buy $bread, $eggs, and $milk from the store.";

Aquí, pone en minúsculas las constantes para que sean más fáciles con los dedos, pero puede eliminar el array_change_key_case () para mantenerlas como están. Si ya tiene nombres de variables locales en conflicto, las constantes no los anularán.

Uso de reemplazo de cadena
Este es similar a sprintf (), pero usa un token de reemplazo único y acepta un número ilimitado de argumentos. Estoy seguro de que hay mejores maneras de hacerlo, pero perdona mi torpeza y trata de concentrarte en la idea detrás de esto.

Como antes, crea una función reutilizable:

function fill(){
    $arr = func_get_args(); $s = $arr[ 0 ]; array_shift( $arr );
    while( strpos( $s, '/' ) !== false ){
        $s = implode( current( $arr ), explode( '/', $s, 2 ) ); next( $arr );
    } return $s;
}

Luego llámalo desde cualquier ámbito:

$s = fill( 'I need to buy /, /, and / from the store.', BREAD, EGGS, MILK );

Puede usar cualquier token de reemplazo que desee, como un% o #. Usé la barra oblicua aquí porque es un poco más fácil de escribir.

Beejor
fuente
0

Es divertido que pueda usar la palabra clave 'const' como nombre para su función para evitar la basura del espacio de nombres:

define("FOO","foo");
${'const'} = function($a){return $a;};
echo "{$const(FOO)}"; // Prints "foo"
echo const(FOO); // Parse error: syntax error, unexpected T_CONST

También puede usar $ GLOBALS para propagar la función 'const' en todo el código:

$GLOBALS['const'] = function($a){return $a;};

No estoy seguro de si es seguro usarlo en el futuro. Y lo que es peor: todavía se ve feo.

usuario619271
fuente
-2

Creo que esto responde a la pregunta original del OP. Lo único es que la clave de índice global parece funcionar solo en minúsculas.

define('DB_USER','root');
echo "DB_USER=$GLOBALS[db_user]";

Salida:

DB_USER=root
Papas Grasas
fuente
1
Esto no parece funcionar (incluso si usa mayúsculas consecutivamente) $ GLOBALS es an associative array containing references to all variables.
har-wradim
Esta respuesta es incorrecta. la única forma en que esto podría producir esa salida es si en algún lugar de tu script también tienes$db_user = 'root';
Jeff Puckett