Uwzględnij stałą w ciągu znaków bez łączenia

166

Czy w PHP jest sposób na umieszczenie stałej w ciągu znaków bez konkatenacji?

define('MY_CONSTANT', 42);

echo "This is my constant: MY_CONSTANT";
Brian
źródło
12
Intuicja podpowiada mi, że „To jest moja stała: {MY_CONSTANT}” powinno działać. Tak nie jest. Tylko wprowadzenie tego tutaj w przypadku gdy ktoś myśli, że samo jak ja
Mikael Lindqvist

Odpowiedzi:

148

Nie.

W przypadku ciągów PHP nie ma sposobu, aby odróżnić dane łańcuchowe od stałych identyfikatorów. Dotyczy to wszystkich formatów ciągów w PHP, w tym heredoc.

constant() jest alternatywnym sposobem na uzyskanie stałej, ale wywołanie funkcji nie może zostać umieszczone w łańcuchu bez konkatenacji.

Podręcznik o stałych w PHP

Pekka
źródło
1
W każdym razie +1, ponieważ jest to niewątpliwie dobra odpowiedź. Najpierw chciałem napisać to samo co Ty, ale po przeczytaniu twojego pomyślałem, że muszę przedstawić coś innego;)
Felix Kling
3
Hehe! Ale zasłużone +1 dla wszystkich za kreatywność. :)
Pekka
59
"wywołanie funkcji nie może być umieszczone w łańcuchu" tak, może:define('ANIMAL','turtles'); $constant='constant'; echo "I like {$constant('ANIMAL')}";
raveren Kwietnia
1
@Raveren, podczas gdy inne oferują pośrednie odmiany, niepotrzebnie tworząc funkcje, twoje jest najkrótszym i do punktu widzenia rozwiązaniem, które opiera się na funkcjach zmiennych, niedocenianej i bardzo rzadko używanej funkcji PHP. Z tego całego wątku wyszedłem z TWOIM konkretnym rozwiązaniem. Chciałbym móc dawać +1 więcej niż raz.
hndcrftd
4
Właśnie wskazałem, że to możliwe, nie komentowałem, który sposób jest lepszy.
raveren
111

Tak to jest (w pewnym sensie;)):

define('FOO', 'bar');

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

Prawdopodobnie nie do tego dążyłeś, ale myślę, że technicznie nie jest to konkatenacja, ale podstawienie iz tego założenia zawiera stałą w łańcuchu bez konkatenacji .

Felix Kling
źródło
5
@Pekka: Wiem :-D (tylko tym razem ...;))
Felix Kling
1
:) Podejście @ juraj.blahunka jest jeszcze bardziej podstępne. Odpowiada na pytanie literą, ale nie duchem. :)
Pekka
2
@blahunka: ładne motto. Prawdopodobnie używamy go codziennie
Alfabravo
57

Aby użyć stałych wewnątrz łańcuchów, możesz użyć następującej metody:

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

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


Jak to działa?

Możesz użyć dowolnej nazwy funkcji łańcuchowej i dowolnych parametrów

Można umieścić dowolną nazwę funkcji w zmiennej i wywołać ją z parametrami wewnątrz łańcucha w cudzysłowie. Działa również z wieloma parametrami.

$fn = 'substr';

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

Produkuje

lubię żółwie

Funkcje anonimowe też

Możesz także korzystać z funkcji anonimowych pod warunkiem, że używasz PHP 5.3+.

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

Zgodnie z oczekiwaniami tworzy prawidłowo zmieniony kod HTML.

Tablice wywołań zwrotnych są niedozwolone!

Jeśli do tej pory masz wrażenie, że nazwa funkcji może być dowolna, tak nie jest, ponieważ tablica zwracająca wartość true po przekazaniu do is_callablespowodowałaby błąd krytyczny, gdy zostanie użyta w ciągu:

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 )}" ); 

Pamiętać

Ta praktyka jest nierozsądna, ale czasami skutkuje znacznie bardziej czytelnym kodem, więc to zależy od Ciebie - taka możliwość istnieje.

raveren
źródło
1
To świetna sztuczka! Podobnie jak inne odpowiedzi, nie jest to duża wygrana w konkatenacji pod względem wysiłku i czytelności, ale miło wiedzieć. Jeszcze bardziej seksowne jest, gdy robisz coś takiego $_ = create_function('$a','return $a;'); $s = "I like {$_(ANIMAL)}". Wersja Thetaiko eliminuje potrzebę cytatów, a podkreślenie jest urocze.
Beejor
2
Widziałem, że jest to przydatne do budowania silnika szablonów, ale wydaje się zbyt podstępne, aby go faktycznie używać.
Mnebuerquo
21
define( 'FOO', 'bar');  
$FOO = FOO;  
$string = "I am too lazy to concatenate $FOO in my string";
Macswork
źródło
4
To jest ten, którego używam najczęściej, kiedy mam do skomponowania kilka szalonych ciągów SQL. A także ... dużo pasywno-agresywny? ;-)
Beejor
2
Ten ma najmniejszą ilość magii kosztem
bycia
Świetne rozwiązanie. Prosto i szybko.
Roger Hill
14
define('FOO', 'bar');
$constants = create_function('$a', 'return $a;');
echo "Hello, my name is {$constants(FOO)}";
thetaiko
źródło
13

Jeśli naprawdę chcesz uzyskać echo stałej bez konkatenacji, oto rozwiązanie:

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

uwaga : w tym przykładzie echo przyjmuje szereg parametrów ( spójrz na przecinki ), więc nie jest to rzeczywiste połączenie

Echo zachowuje się jak funkcja, pobiera więcej parametrów, jest bardziej wydajne niż konkatenacja, ponieważ nie musi konkatenować, a potem odbijać, po prostu odbija wszystko bez konieczności tworzenia nowego obiektu łączonego String :))

EDYTOWAĆ

Również jeśli weźmiesz pod uwagę łączenie łańcuchów, przekazywanie łańcuchów jako parametry lub pisanie całych ciągów z " ," , (wersja z przecinkiem) jest zawsze najszybsza, następny idzie . (Konkatenacja z ' pojedynczymi cudzysłowami) a najwolniejsza metoda budowania ciągów używa podwójnych cudzysłowów " , ponieważ wyrażenia napisane w ten sposób muszą być oceniane w odniesieniu do zadeklarowanych zmiennych i funkcji.

Juraj Blahunka
źródło
11

Mógłbyś:

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']}";
Szymon
źródło
6

Najłatwiej jest

define('MY_CONSTANT', 42);

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

Inny sposób użycia (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
źródło
Uważam to za dobre rozwiązanie. W niektórych przypadkach, connect string nie zadziała, jeśli użyjesz direct CONSTANT wewnątrz.
kta
5

Jak zauważyli inni, nie możesz tego zrobić. PHP ma funkcję, constant()której nie można wywołać bezpośrednio w ciągu znaków, ale możemy łatwo obejść ten problem.

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

i podstawowy przykład użycia:

define('FOO', 'Hello World!');
echo "The string says {$constant('FOO')}"; 
Yamiko
źródło
Możesz po prostu zrobić $constant = 'constant';zamiast definiować inną funkcję i będzie działać identycznie, ponieważ ta funkcja już istnieje.
redreinard
2

Oto kilka alternatyw dla innych odpowiedzi, które wydają się być skoncentrowane głównie na sztuczce „{$}”. Chociaż nie ma gwarancji co do ich szybkości; to wszystko jest czysty cukier syntaktyczny. W tych przykładach przyjmiemy, że zdefiniowano poniższy zestaw stałych.

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

Używanie ekstraktu ()
To jest fajne, ponieważ wynik jest identyczny ze zmiennymi. Najpierw utwórz funkcję wielokrotnego użytku:

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

Następnie wywołaj to z dowolnego zakresu:

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

Tutaj zmniejsza stałe, aby być łatwiejszym dla palców, ale możesz usunąć array_change_key_case (), aby zachować je bez zmian. Jeśli masz już sprzeczne nazwy zmiennych lokalnych, stałe ich nie zastąpią.

Używanie zamiany ciągów znaków
Ta metoda jest podobna do sprintf (), ale używa pojedynczego tokenu zastępczego i przyjmuje nieograniczoną liczbę argumentów. Jestem pewien, że istnieją lepsze sposoby, aby to zrobić, ale wybacz moją niezdarność i spróbuj skupić się na idei, która za tym stoi.

Tak jak poprzednio, tworzysz funkcję wielokrotnego użytku:

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;
}

Następnie wywołaj to z dowolnego zakresu:

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

Możesz użyć dowolnego tokena zastępczego, takiego jak% lub #. Użyłem tutaj ukośnika, ponieważ wpisywanie jest nieco łatwiejsze.

Beejor
źródło
0

To zabawne, że możesz użyć słowa kluczowego „const” jako nazwy swojej funkcji, aby zapobiec zaśmiecaniu przestrzeni nazw:

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

Możesz także użyć $ GLOBALS do propagowania funkcji 'const' w całym kodzie:

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

Nie jestem pewien, czy można go bezpiecznie używać w przyszłości. A co gorsza - nadal wygląda brzydko.

user619271
źródło
-2

Myślę, że to odpowiada na pierwotne pytanie PO. Jedyną rzeczą jest to, że klucz indeksu globals wydaje się działać tylko z małymi literami.

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

Wynik:

DB_USER=root
Tłuste Ziemniaki
źródło
1
Wydaje się, że to nie działa (nawet jeśli używasz kolejno wielkich liter) $ GLOBALS jest an associative array containing references to all variables.
har-wradim
ta odpowiedź jest błędna. Tylko w ten sposób, że może to być może produkować to wyjście jest, jeśli gdzieś w skrypcie masz również$db_user = 'root';
Jeff Puckett