Zdefiniuj () vs. const

659

W PHP, kiedy używasz

define('FOO', 1);

i kiedy używasz

const FOO = 1;

?

Jakie są główne różnice między tymi dwoma?

Danjarvis
źródło
4
O wydajności (strata czasu z mikrooptymalizacją jak ja), zobacz tę odpowiedź : constjest dwa razy szybsza niż define. Informacje o czasie ładowania strony i zużyciu pamięci: zobacz to pytanie i ten artykuł ... Zobacz także coś o pamięci podręcznej opcode tutaj .
Peter Krauss
2
Nie patrz tylko na aktualnie zaakceptowaną odpowiedź, ale spójrz na stackoverflow.com/a/3193704/1412157, tak jak powinna być zaakceptowana odpowiedź
LucaM
1
Właśnie zobaczyłem powiadomienie o Twoim komentarzu. Zaktualizowałem zaakceptowaną odpowiedź.
danjarvis

Odpowiedzi:

1039

W PHP 5.3 istnieją dwa sposoby definiowania stałych : albo za pomocą constsłowa kluczowego, albo za pomocą define()funkcji:

const FOO = 'BAR';
define('FOO', 'BAR');

Podstawowa różnica między tymi dwoma sposobami polega na tym, że constdefiniuje stałe w czasie kompilacji, a definedefiniuje je w czasie wykonywania. To powoduje większość constwad. Niektóre wady const:

  • constnie można używać do warunkowego definiowania stałych. Aby zdefiniować stałą globalną, należy jej użyć w najbardziej zewnętrznym zakresie:

    if (...) {
        const FOO = 'BAR';    // Invalid
    }
    // but
    if (...) {
        define('FOO', 'BAR'); // Valid
    }

    Dlaczego i tak chcesz to zrobić? Jedną z typowych aplikacji jest sprawdzenie, czy stała jest już zdefiniowana:

    if (!defined('FOO')) {
        define('FOO', 'BAR');
    }
  • constPrzyjmuje skalarne statycznego (liczba znaków lub innych stałej jak true, false, null, __FILE__), przy czym define()bierze żadnej wypowiedzi. Ponieważ dozwolone są również wyrażenia stałe PHP 5.6 const:

    const BIT_5 = 1 << 5;    // Valid since PHP 5.6 and invalid previously
    define('BIT_5', 1 << 5); // Always valid
  • constprzyjmuje zwykłą stałą nazwę, ale define()akceptuje każde wyrażenie jako nazwę. Pozwala to robić takie rzeczy:

    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
  • consts zawsze rozróżniają małe i wielkie litery, podczas gdy define()pozwala ci definiować stałe bez rozróżniania wielkości liter, przekazując truejako trzeci argument (Uwaga: definiowanie stałych bez rozróżniania wielkości liter jest przestarzałe od PHP 7.3.0.):

    define('FOO', 'BAR', true);
    echo FOO; // BAR
    echo foo; // BAR

To była zła strona. Spójrzmy teraz na powód, dla którego osobiście zawsze używam, constchyba że wystąpi jedna z powyższych sytuacji:

  • constpo prostu ładniej czyta. Jest to konstrukcja języka zamiast funkcji, a także jest spójna z tym, jak definiujesz stałe w klasach.
  • const, będący konstrukcją językową, może być analizowany statycznie za pomocą zautomatyzowanych narzędzi.
  • constdefiniuje stałą w bieżącej przestrzeni nazw, natomiast define()należy przekazać pełną nazwę przestrzeni nazw:

    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
  • Ponieważ conststałe PHP 5.6 mogą być również tablicami, a jednocześnie define()nie obsługują tablic. Jednak tablice będą obsługiwane dla obu przypadków w PHP 7.

    const FOO = [1, 2, 3];    // Valid in PHP 5.6
    define('FOO', [1, 2, 3]); // Invalid in PHP 5.6 and valid in PHP 7.0

Na koniec zauważ, że constmożna go również użyć w klasie lub interfejsie do zdefiniowania stałej klasy lub stałej interfejsu. definenie można użyć do tego celu:

class Foo {
    const BAR = 2; // Valid
}
// But
class Baz {
    define('QUX', 2); // Invalid
}

Podsumowanie

O ile nie potrzebujesz żadnej definicji warunkowej lub wyrażeniowej, użyj consts zamiast define()s - po prostu ze względu na czytelność!

NikiC
źródło
1
Jak wiem z PHP 5.6, będziesz mieć możliwość korzystania z prostych wyrażeń skalarnych nawet z constkonstrukcją języka - patrz wiki.php.net/rfc/const_scalar_exprs
mabe.berlin
6
Inną korzyścią z używania constjest brak cudzysłowów, co oznacza, że ​​jest sformatowany tak samo, jak jest używany w twoim IDE.
rybo111
3
To powinno być to, co jest w dokumentach PHP. To najlepsze wytłumaczenie, jakie widziałem, szczególnie część, o której większość ludzi zapomina (kompilacja vs. środowisko uruchomieniowe).
James
4
define('a', $_GET['param']);, const b = a;działa idealnie i otrzymuje wartość, gdy const c = $_GET['param'];jest niepoprawna. Czy constnaprawdę jest czas kompilacji? Raczej nie sądzę ... (testowane na PHP 7.0.7)
mcserep
1
wiki.php.net/rfc/case_insensitive_constant_deprecationW PHP 8.0: Usuń możliwość deklarowania stałych bez rozróżniania wielkości liter. ” dla każdego, kto podejmie się tutaj w przyszłości w odniesieniu do rozróżniania wielkości liter
Scuzzy
196

Do PHP 5.3 constnie można było używać go w zakresie globalnym. Możesz użyć tego tylko z klasy. Należy tego użyć, gdy chcesz ustawić jakąś stałą opcję lub ustawienie, które dotyczy tej klasy. A może chcesz stworzyć jakiś wyliczenie.

definemożna użyć do tego samego celu, ale można go użyć tylko w zakresie globalnym. Należy go używać tylko do ustawień globalnych, które wpływają na całą aplikację.

Przykładem dobrego constużycia jest pozbycie się magicznych liczb. Spójrz na stałe PDO . Gdy musisz określić typ pobierania, wpisz PDO::FETCH_ASSOCna przykład. Gdyby consts nie były używane, skończyłbyś pisaniem czegoś takiego 35(lub cokolwiek FETCH_ASSOCzdefiniowanego jako). To nie ma sensu dla czytelnika.

Przykładem dobrego defineużycia może być określenie ścieżki katalogu głównego aplikacji lub numeru wersji biblioteki.

ryeguy
źródło
12
Warto wspomnieć o użyciu constz przestrzeniami nazw.
salathe
31
Należy również zauważyć, że PHP5.3 może bardzo dużo używać const w zakresie globalnym.
Gordon,
5.2 może również. Piękno consts vs. definiuje to, że musisz poprzedzić je nazwą klasy. Korzystanie z nich sprawia, że ​​kod jest bardziej czytelny i ładniejszy. To dla mnie bonus.
lucifurious
1
@ryeguy, ale co z wersją PHP 5.3, gdzie const może być używany globalnie, tak jak zdefiniuj?
andho
1
@ andho, zrób kolejny krok do tańca PHP o jeden krok do przodu, jeden krok do tyłu, taniec „ulepszeń”. On. :)
Umowa prof. Falkena została naruszona
37

Wiem, że już na nie odpowiedziano, ale żadna z obecnych odpowiedzi nie wspomina o przestrzeni nazw i jej wpływie na stałe i definicje.

Począwszy od PHP 5.3, consts i definicje są podobne pod wieloma względami. Wciąż jednak istnieją pewne ważne różnice:

  • Stałych nie można zdefiniować na podstawie wyrażenia. const FOO = 4 * 3;nie działa, ale define('CONST', 4 * 3);działa.
  • Nazwa przekazywana do definemusi zawierać przestrzeń nazw, która ma zostać zdefiniowana w tej przestrzeni nazw.

Poniższy kod powinien zilustrować różnice.

namespace foo 
{
    const BAR = 1;
    define('BAZ', 2);
    define(__NAMESPACE__ . '\\BAZ', 3);
}

namespace {
    var_dump(get_defined_constants(true));
}

Zawartość pod-macierzy użytkownika będzie ['foo\\BAR' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3].

=== AKTUALIZACJA ===

Nadchodzący PHP 5.6 pozwoli na nieco większą elastyczność const. Będziesz teraz mógł definiować stałe w kategoriach wyrażeń, pod warunkiem, że wyrażenia te składają się z innych stałych lub literałów. Oznacza to, że następujące informacje powinny obowiązywać od 5.6:

const FOOBAR = 'foo ' . 'bar';
const FORTY_TWO = 6 * 9; // For future editors: THIS IS DELIBERATE! Read the answer comments below for more details
const ULTIMATE_ANSWER = 'The ultimate answer to life, the universe and everything is ' . FORTY_TWO;

Jednak nadal nie będziesz w stanie zdefiniować stałych w kategoriach zmiennych lub zwrotów funkcji, więc

const RND = mt_rand();
const CONSTVAR = $var;

nadal będzie niedostępny.

GordonM
źródło
8
Nie mogłem się powstrzymać od pytania: czy świadomie zdefiniowałeś FORTY_TWOjako 54?
Punchlinern
9
„Sześć na dziewięć? Czterdzieści dwa? Zawsze mówiłem, że z wszechświatem było coś zasadniczo nie tak”. Sprawdź dzieła Douglasa Adamsa, jeśli potrzebujesz pełnego wyjaśnienia.
GordonM,
2
O. Byłem świadomy, że 42 to odpowiedź na życie, wszechświat i wszystko, ale brakowało mi Szóstki o dziewięć części. Dziękuję za wyjaśnienie!
Punchlinern
20

define Używam dla stałych globalnych.

const Używam dla stałych klas.

Nie możesz definewchodzić w zakres zajęć, a wraz z consttobą możesz. Nie trzeba dodawać, że nie można używać constpoza zakresem klasy.

Ponadto, z const, faktycznie staje się członkiem klasy, a z define, zostanie przesunięty do zasięgu globalnego.

Jacob Relkin
źródło
8
Jak zauważono w innych odpowiedziach, const może być używany poza klasami w PHP 5.3+
MrWhite
Do utworzenia stałej w przestrzeni nazw można użyć tylko słowa kluczowego const, nie tylko klas
Alireza Rahmani Khalili,
16

Odpowiedź NikiC jest najlepsza, ale pozwól mi dodać nieoczywiste zastrzeżenie podczas korzystania z przestrzeni nazw, abyś nie złapał się na nieoczekiwanym zachowaniu. Należy pamiętać, że definicje są zawsze w globalnej przestrzeni nazw, chyba że jawnie dodasz przestrzeń nazw jako część identyfikatora definicji. Nie jest w tym oczywiste, że identyfikator przestrzeni nazw przebija identyfikator globalny. Więc :

<?php
namespace foo
{
  // Note: when referenced in this file or namespace, the const masks the defined version
  // this may not be what you want/expect
  const BAR = 'cheers';
  define('BAR', 'wonka');

  printf("What kind of bar is a %s bar?\n", BAR);

  // To get to the define in the global namespace you need to explicitely reference it
  printf("What kind of bar is a %s bar?\n", \BAR);
}

namespace foo2
{
  // But now in another namespace (like in the default) the same syntax calls up the 
  // the defined version!
  printf("Willy %s\n", BAR);
  printf("three %s\n", \foo\BAR);  
}
?>

produkuje:

What kind of bar is a cheers bar? 
What kind of bar is a wonka bar?
willy wonka 
three cheers

Co dla mnie sprawia, że ​​całe pojęcie const jest niepotrzebnie mylące, ponieważ idea const w kilkudziesięciu innych językach jest taka, że ​​zawsze jest taka sama, gdziekolwiek jesteś w kodzie, a PHP tak naprawdę tego nie gwarantuje.

slartibartfast
źródło
1
Tak, ale BARi \foo\BARto tylko nie te same stałe. Zgadzam się, że to naprawdę mylące, ale jeśli weźmiesz również pod uwagę, że logika przestrzeni nazw jest spójna w ten sposób, i że ani constani nie define()jest jak makro C ( #define), to PHP może mieć jakąś wymówkę.
Sz.
1
Pojęcie stałej jest dokładnie takie, jak powinno się zachowywać - jesteś w przestrzeni nazw! Chcesz go bez identyfikatora przestrzeni nazw, a następnie utwórz go poza przestrzenią nazw. Uczyni to również spójność ze stałą zdefiniowaną w klasie, nawet jeśli używa innej składni. Tak, definicja jest również spójna, w inny sposób.
Gerard ONeill
12

Większość tych odpowiedzi jest błędna lub mówi tylko połowę historii.

  1. Możesz zawęzić zakres przy użyciu przestrzeni nazw.
  2. Możesz użyć słowa kluczowego „const” poza definicjami klas. Jednak, podobnie jak w klasach, wartości przypisane za pomocą słowa kluczowego „const” muszą być wyrażeniami stałymi.

Na przykład:

const AWESOME = 'Bob'; // Valid

Zły przykład:

const AWESOME = whatIsMyName(); // Invalid (Function call)
const WEAKNESS = 4+5+6; // Invalid (Arithmetic) 
const FOO = BAR . OF . SOAP; // Invalid (Concatenation)

Aby utworzyć stałe zmiennych, użyj funkcji replace () w następujący sposób:

define('AWESOME', whatIsMyName()); // Valid
define('WEAKNESS', 4 + 5 + 6); // Valid
define('FOO', BAR . OF . SOAP); // Valid
AwesomeBobX64
źródło
1
PHP> = 5.6 wprowadzono pewne zmiany w kompilatorze Zend Engine i const jest teraz traktowany w inny sposób.
Ankit Vishwakarma
6

Tak, const są definiowane w czasie kompilacji, a ponieważ stanom nikic nie można przypisać wyrażenia, tak jak można zdefiniować (). Ale również stałych nie można warunkowo zadeklarować (z tego samego powodu). to znaczy. Nie możesz tego zrobić:

if (/* some condition */) {
  const WHIZZ = true;  // CANNOT DO THIS!
}

Podczas gdy można to zrobić za pomocą definicji (). Tak więc tak naprawdę nie sprowadza się to do osobistych preferencji, istnieje poprawny i niewłaściwy sposób korzystania z obu.

Na marginesie ... Chciałbym zobaczyć jakąś klasę const, której można przypisać wyrażenie, rodzaj definicji (), którą można odizolować od klas?

MrWhite
źródło
5

Aby dodać odpowiedź NikiC. constmogą być używane w ramach klas w następujący sposób:

class Foo {
    const BAR = 1;

    public function myMethod() {
        return self::BAR;
    }
}

Nie możesz tego zrobić za pomocą define().

Marcus Lind
źródło
4

Nikt nie mówi nic o php-doc, ale dla mnie jest to również bardzo znaczący argument za preferencją const:

/**
 * My foo-bar const
 * @var string
 */
const FOO = 'BAR';
Николай Лубышев
źródło
0

Dzięki funkcji definiowania stałej słowa kluczowego uzyskasz możliwość rozróżniania wielkości liter, ale ze słowem kluczowym const nie.

define("FOO", 1, true);
echo foo; //1
echo "<br/>";
echo FOO; //1
echo "<br/>";

class A {
  const FOO = 1;
}

echo A::FOO; //valid
echo "<br/>";

//but

class B {
  define FOO = 1; //syntax error, unexpected 'define'
}

echo B::FOO; //invalid
GaziAnis
źródło