Sprawdzone metody: praca z długimi, wielowierszowymi ciągami znaków w PHP?

177

Uwaga: przepraszam, jeśli jest to niezwykle proste pytanie, ale mam pewną obsesję kompulsywną w kwestii formatowania mojego kodu.

Mam klasę, która ma funkcję, która zwraca ciąg znaków, który będzie stanowić treść wiadomości e-mail. Chcę, aby ten tekst był sformatowany, aby wyglądał dobrze w e-mailu, ale także, aby mój kod nie wyglądał dziwnie. Oto o co mi chodzi:

class Something
{
    public function getEmailText($vars)
    {
        $text = 'Hello ' . $vars->name . ",

The second line starts two lines below.

I also don't want any spaces before the new line, so it's butted up against the left side of the screen.";
        return $text;
    }
}

ale można go również zapisać jako:

public function getEmailText($vars)
{
    $text = "Hello {$vars->name},\n\rThe second line starts two lines below.\n\rI also don't want any spaces before the new line, so it's butted up against the left side of the screen.";
    return $text;
}

ale o co chodzi z nowymi liniami i powrotami karetki? Co za różnica? Czy \n\njest odpowiednikiem \r\rlub \n\r? Którego należy użyć, gdy tworzę przerwę między wierszami?

Następnie jest opcja buforowania wyjścia i składni heredoc.

Jak sobie radzisz z używaniem długich wielowierszowych ciągów w swoich obiektach?

Andrzej
źródło
3
Zawsze myślałem, że \ n to nowa linia w Uniksie \ r to nowa linia w systemie MacOS przed OS / X, a \ r \ n to nowa linia w systemie Windows. Ponadto, biorąc pod uwagę, że będzie to ciąg znaków, który pojawia się w wiadomości e-mail, będziesz chciał się upewnić, że niezależnie od tego, w jaki sposób to robisz, pojawia się poprawnie na większości klientów poczty poleceń. Wskazówka: program Outlook w niektórych przypadkach usuwa dodatkowe znaki nowej linii, więc nie zawsze otrzymasz to, czego oczekujesz.
Kenny Drobnack
1
Nie jestem pewien, czy to wszystko jest takie ważne, ale pierwotnie dwa znaki „nowego wiersza” pochodziły z fizycznej maszyny do pisania, która używała dwóch znaków. Jeden do umieszczenia karetki z powrotem po lewej stronie strony (CR - 0xD) i taki, który spowodował przejście strony do następnej linii (LF - 0xA). Jestem pewien, że są ludzie, którzy wiedzą więcej na ten temat jednak.
mkgrunder

Odpowiedzi:

289

Powinieneś użyć HEREDOC lub NOWDOC.

$var = "some text";
$text = <<<EOT
  Place your text between the EOT. It's
  the delimiter that ends the text
  of your multiline string.
  $var
EOT;

Różnica między Heredoc i Nowdoc polega na tym, że kod PHP osadzony w heredoc jest wykonywany, podczas gdy kod PHP w Nowdoc zostanie wydrukowany bez zmian.

$var = "foo";
$text = <<<'EOT'
  My $var
EOT;

W tym przypadku $ text będzie miał wartość My $var.

Uwaga: przed zamknięciem EOT;nie powinno być spacji ani tabulatorów. w przeciwnym razie pojawi się błąd

halfdan
źródło
Czemu? Ponieważ wszystko między pierwszym EOT a drugim jest uważane za ciąg taki, jaki jest. Co oznacza, że ​​nie musisz umieszczać odwrotnego ukośnika n na wszystkich wieloliniowych ciągach. @Fabian: Jaka jest różnica między HEREDOC i NOWDOC, czy też są tym samym?
Kenny Drobnack
4
@powtac: Nie, ponieważ musi znajdować się w nowej linii, aby zakończyć heredoc. W szczególności musi być EOT;bez spacji przed nim.
Powerlord
Dodałem wyjaśnienie dla Nowdoc.
halfdan
6
@halfdan, czy coś mi brakuje? Po co zawracać sobie głowę heredocsami i nowdocs, skoro możemy po prostu wpisać klawisz „Enter” i otoczyć wielowierszowy ciąg cudzysłowami, tak jak zwykły ciąg?
Pacerier,
3
Po prostu dodaj to do swojej odpowiedzi: przed ostatnią EOT;nie powinno być spacji ani tabulatorów. w przeciwnym razie pojawi się błąd.
Shnd
44

Używam podobnego systemu co pix0r i myślę, że dzięki temu kod jest całkiem czytelny. Czasami posunąłbym się nawet do oddzielenia podziałów wierszy w podwójnych cudzysłowach i użycia pojedynczych cudzysłowów dla pozostałej części ciągu. W ten sposób wyróżniają się od reszty tekstu, a zmienne również wyróżniają się lepiej, jeśli używasz konkatenacji, zamiast wstawiać je w łańcuch w podwójnym cudzysłowie. Mogę więc zrobić coś takiego na Twoim oryginalnym przykładzie:

$text = 'Hello ' . $vars->name . ','
      . "\r\n\r\n"
      . 'The second line starts two lines below.'
      . "\r\n\r\n"
      . 'I also don\'t want any spaces before the new line,'
      . ' so it\'s butted up against the left side of the screen.';

return $text;

Jeśli chodzi o podziały wierszy, w przypadku e-maili należy zawsze używać \ r \ n. PHP_EOL jest przeznaczone dla plików, które mają być używane w tym samym systemie operacyjnym, w którym działa php.

Cvuorinen
źródło
Czy ustawiłeś to wcięcie w swoim IDE (aby ustawić wielowierszowy ciąg wyrównany do każdej części)?
Krzysztof Trzos
25

Używam szablonów do długiego tekstu:

email-template.txt zawiera

hello {name}!
how are you? 

W PHP robię to:

$email = file_get_contents('email-template.txt');
$email = str_replace('{name},', 'Simon', $email);
powtac
źródło
ciekawe ... gdzie przechowujesz swoje szablony w strukturze katalogów aplikacji internetowej?
Andrew,
Mój kod to tylko demo. W przypadku ogromnej aplikacji internetowej możesz użyć struktury takiej jak / templates / e-mail /, / templates / userfeedback /. Ale jeśli masz więcej rzeczy, poleciłbym pełny system szablonów, taki jak SMARTY.
powtac
Dwoo dwoo.org to przyzwoity system szablonów PHP zgodny ze SMARTY, który niektórzy uważają za dobrego następcę (zaczął na PHP5, więc nie ma bagażu w PHP4).
micahwittman
19

Dodawanie \ni / lub \rw środku łańcucha i posiadanie bardzo długiej linii kodu, jak w drugim przykładzie, nie wydaje się właściwe: kiedy czytasz kod, nie widzisz wyniku i musisz przewijać .

W tego rodzaju sytuacjach zawsze używam Heredoc (lub Nowdoc, jeśli używam PHP> = 5.3) : łatwe do napisania, łatwe do odczytania, nie ma potrzeby stosowania bardzo długich wierszy, ...

Na przykład :

$var = 'World';
$str = <<<MARKER
this is a very
long string that
doesn't require
horizontal scrolling, 
and interpolates variables :
Hello, $var!
MARKER;

Tylko jedno: znacznik końcowy (i „ ;” po nim) musi być jedyną rzeczą w tym wierszu: bez spacji / tabulacji przed ani po!

Pascal MARTIN
źródło
12

Jasne, możesz użyć HEREDOC, ale jeśli chodzi o czytelność kodu, nie jest to tak naprawdę lepsze niż pierwszy przykład, zawijając ciąg w wiele linii.

Jeśli naprawdę chcesz, aby Twój wieloliniowy ciąg wyglądał dobrze i dobrze płynął z Twoim kodem, polecam łączenie ciągów w taki sposób:

$text = "Hello, {$vars->name},\r\n\r\n"
    . "The second line starts two lines below.\r\n"
    . ".. Third line... etc";

Może to być nieco wolniejsze niż HEREDOC lub ciąg wieloliniowy, ale będzie dobrze płynąć z wcięciem twojego kodu i ułatwi czytanie.

pix0r
źródło
9

Trochę bardziej podoba mi się ta metoda w Javascript, ale wydaje się, że warto ją tutaj uwzględnić, ponieważ nie została jeszcze wspomniana.

$var = "pizza";

$text = implode(" ", [
  "I love me some",
  "really large",
  $var,
  "pies.",
]);

// "I love me some really large pizza pies."

W przypadku mniejszych rzeczy często łatwiej jest pracować ze strukturami tablicowymi w porównaniu z połączonymi ciągami.

Powiązane: implode vs concat performance

Jasio
źródło
1

Ten, który w to wierzy

"abc\n" . "def\n"

czy ciąg wielowierszowy jest nieprawidłowy. To dwa łańcuchy z operatorem konkatenacji, a nie ciąg wielowierszowy. Takich połączonych ciągów nie można na przykład używać jako kluczy predefiniowanych tablic. Niestety php nie oferuje prawdziwych ciągów wielowierszowych w postaci

"abc\n"
"def\n"

tylko HEREDOCi NOWDOCskładnię, która jest bardziej odpowiednia dla szablonów, ponieważ zagnieżdżone wcięcie kodu jest łamane przez taką składnię.

Dmitriy Sintsov
źródło
1

możesz także użyć:

<?php
ob_start();
echo "some text";
echo "\n";

// you can also use: 
?> 
some text can be also written here, or maybe HTML:
<div>whatever<\div>
<?php
echo "you can basically write whatever you want";
// and then: 
$long_text = ob_get_clean();
Alon Gouldman
źródło
0

Jeśli chodzi o pytanie dotyczące nowych linii i zwrotów karetek:

Zalecałbym użycie predefiniowanej globalnej stałej PHP_EOL, ponieważ rozwiąże ona wszelkie problemy ze zgodnością między platformami.

To pytanie zostało zadane wcześniej w SO i możesz uzyskać więcej informacji, czytając „ Kiedy używam stałej PHP PHP_EOL

Corey Ballou
źródło
1
Komentarz do tej odpowiedzi sugeruje, że powinienem używać \ r \ n do nowych wierszy w wiadomościach e-mail: stackoverflow.com/questions/128560/ ...
Andrew
0

ale o co chodzi z nowymi liniami i powrotami karetki? Co za różnica? Czy \ n \ n jest odpowiednikiem \ r \ r lub \ n \ r? Którego należy użyć, gdy tworzę przerwę między wierszami?

Nikt tutaj chyba nie odpowiedział na to pytanie, więc oto jestem.

\r reprezentuje „powrót karetki”

\n reprezentuje „wysuw o wiersz”

Rzeczywista przyczyna ich powstania sięga maszyn do pisania. W miarę wpisywania tekstu „karetka” przesuwał się powoli, znak po znaku, na prawo od maszyny do pisania. Gdy dojdziesz do końca linii, wrócisz karetką, a następnie udasz się do nowej linii . Aby przejść do nowego wiersza, należy przesunąć dźwignię, która podawała wiersze pisarzowi. W związku z tym te działania, łącznie, nazwano wysuwem wiersza powrotu karetki . A więc dosłownie:

Kanał linia, \noznacza przejście do następnej linii.

Powrót karetki \roznacza przesunięcie kursora na początek wiersza.

Ostatecznie Hello\n\nWorldna ekranie powinien pojawić się następujący wynik:

Hello

     World

Gdzie Hello\r\rWorldpowinno skutkować następującym wyjściem .

Dopiero łącząc te 2 znaki \r\n, masz wspólne rozumienie znanej linii. IE Hello\r\nWorldpowinno skutkować:

Hello
World

I oczywiście \n\rdałoby taki sam efekt wizualny jak \r\n.

Pierwotnie komputery brały \ri \ndosłownie. Jednak w dzisiejszych czasach poparcie dla powrotu karetki jest niewielkie. Zwykle w każdym systemie możesz uciec z \nsamodzielnym używaniem . To nigdy nie zależy od systemu operacyjnego, ale zależy od tego, w czym przeglądasz dane wyjściowe.

Mimo to zawsze radziłbym używać, \r\ngdzie tylko możesz!

Sancarn
źródło