HEREDOC dizeleri içinde PHP işlevlerini çağırma


94

PHP'de HEREDOC dizge bildirimleri bir html bloğunun çıktısını almak için gerçekten kullanışlıdır. Değişkenleri sadece $ önekiyle ayrıştırmasını sağlayabilirsiniz, ancak daha karmaşık sözdizimi için ($ var [2] [3] gibi), ifadenizi {} parantez içine koymalısınız.

PHP 5, ise aslında bir heredoc dize içinde {} parantezler içinde işlev çağrıları yapmak mümkün, ama işe biraz geçmesi gerekiyor. İşlev adının kendisi bir değişkende saklanmalıdır ve onu dinamik olarak adlandırılmış bir işlevmiş gibi çağırmanız gerekir. Örneğin:

$fn = 'testfunction';
function testfunction() { return 'ok'; }
$string = <<< heredoc
plain text and now a function: {$fn()}
heredoc;

Gördüğünüz gibi, bu sadece şunlardan biraz daha karmaşık:

$string = <<< heredoc
plain text and now a function: {testfunction()}
heredoc;

İlk kod örneğinin yanı sıra, işlevi çağırmak için HEREDOC'tan çıkmak veya sorunu tersine çevirmek ve aşağıdaki gibi bir şey yapmak gibi başka yollar da vardır:

?>
<!-- directly output html and only breaking into php for the function -->
plain text and now a function: <?PHP print testfunction(); ?>

İkincisi, çıktının doğrudan çıkış akışına yerleştirilmesi dezavantajına sahiptir (çıktı tamponlamasını kullanmıyorsam), ki bu istediğim şey olmayabilir.

Öyleyse, sorumun özü şudur: buna yaklaşmanın daha zarif bir yolu var mı?

Yanıtlara göre düzenleme: Kesinlikle bir tür şablon motoru hayatımı çok daha kolaylaştıracak gibi görünüyor, ancak temelde her zamanki PHP stilimi tersine çevirmemi gerektirecek. Bu kötü bir şey değil, ama ataletimi açıklıyor .. Hayatı kolaylaştırmanın yollarını bulmaya hazırım, bu yüzden şimdi şablonlara bakıyorum.


3
Bu kesinlikle sorunuza bir cevap değil, ancak yorumlu ifadelerdeki işlev çağrıları için yetersiz destek göz önüne alındığında, genellikle heredocu yazdırmadan önce ihtiyaç duyacağım dizeleri oluşturuyorum. O halde, Text {$string1} Text {$string2} Textheredokta olduğu gibi basitçe kullanabilirim .
rinogo

Yanıtlar:


51

Kişisel olarak HEREDOC'u bunun için kullanmam. Sadece iyi bir "şablon oluşturma" sistemi yapmaz. Tüm HTML'niz birkaç dezavantajı olan bir dizede kilitlenmiştir

  • WYSIWYG için seçenek yok
  • IDE'lerden HTML için kod tamamlama yok
  • Çıkış (HTML) mantık dosyalarına kilitlendi
  • Döngü gibi daha karmaşık şablonlar elde etmek için şu anda yapmaya çalıştığınız gibi hack kullanmak zorunda kalıyorsunuz.

Basit bir şablon motoru edinin veya sadece içerilenlerle PHP'yi kullanın - bu yüzden dilin <?phpve ?>sınırlayıcıları vardır.

template_file.php

<html>
<head>
  <title><?php echo $page_title; ?></title>
</head>
<body>
  <?php echo getPageContent(); ?>
</body>

index.php

<?php

$page_title = "This is a simple demo";

function getPageContent() {
    return '<p>Hello World!</p>';
}

include('template_file.php');

8
Echo için bir kısaltma vardır: <?=$valueToEcho;?>veya <%=$valueToEcho;%>INI ayarlarınıza bağlı.
Peter Bailey

3
Bu stenografi kullanımıyla ilgili okuduğum çoğu şey, onları kullanmanın kötü bir uygulama olduğunu söylüyor ve ben de aynı fikirdeyim. Bu nedenle, maalesef dağıtım için kod yazıyorsanız, bu INI ayarlarına güvenemezsiniz, bu nedenle PHP'nin onlar için "desteğini" dağıtılmış kod için tartışmalı hale getirirsiniz. FWIW, bu kısayolları kullandıkları için başkalarının WordPress eklentilerindeki hataları bir kereden fazla düzeltmek zorunda kaldım.
MikeSchinkel

1
Hayır, 7 karakter yazmam çok yazık demiyorum; benim sorunlarımı yanlış anlıyorsun. Benim ilgilendiğim yazı yazmak değil , okumak . Bu karakterler, kaynak kodunu taramayı ve kodun ne yaptığını anlamayı çok daha zor hale getiren çok sayıda görsel gürültü yaratır. En azından benim için bir HEREDOC okumak ÇOK daha kolay. (Ve BTW, verilen bir HTML parçasında kaç kez kullanıldığına dair 7 karakterlik bir süredir. Ama konu
dışına çıkıyorum

12
Kısa, daha güzel, daha temiz ve okunması daha kolay. Senin görünümlerinde <?=$title?>olduğu kadar <? Php echo $ başlığı daha güzel; ?>. Olumsuz tarafı, evet, dağıtım için birçok ini'nin kısa etiketleri kapalı. Ama tahmin et ne oldu? İtibariyle PHP 5.4 , kısa etiketler ini ayarlardan bağımsız PHP'de etkinleştirilmiş! Öyleyse, 5.4+ gereksinimiyle kodluyorsanız (örneğin, özellikleri kullandığınızı varsayalım), devam edin ve bu harika kısa etiketleri kullanın !!
Jimbo

2
Bu arada <? = $ Blah?>, Kısa etiketler kapatılsa bile varsayılan olarak 5.4'te etkinleştirilmiştir.
callmetwan

73

Bunu gerçekten yapmak istiyorsanız, ancak bir sınıfı kullanmaktan biraz daha basitse, kullanabilirsiniz:

function fn($data) {
  return $data;
}
$fn = 'fn';

$my_string = <<<EOT
Number of seconds since the Unix Epoch: {$fn(time())}
EOT;

Harika @CJDennis! HEREDOC içindeki fonksiyonları kullanmak için en iyi ve en temiz çözüm budur. Bazı durumlarda güzel kaynaklar var. Sitemde, tabindex konumu oluşturmak için işlev çağrısı ile 22 satırlık alan kümeleri (bir FOR döngüsü içindeki HEREDOC bloğu) içeren formlar oluşturmak için HEREDOC kullanıyorum.
Paulo Buchsbaum

Bunu bile yapabilirsiniz:$my_string = "Half the number of seconds since the Unix Epoch: {$fn(time() / 2 . ' Yes! Really!')}";
CJ Dennis

2
daha kompakt bir tanım: $fn = function fn($data) { return $data; };
devsmt

1
@devsmt Haklısın. Daha da kısası:$fn = function ($data) { return $data; };
CJ Dennis

oh, Godegolf? tamam beni içeri: $fn=function($data){return $data;};rhis kısa olmalıdır
MY1

43

Ben şunu yapardım:

$string = <<< heredoc
plain text and now a function: %s
heredoc;
$string = sprintf($string, testfunction());

Bunun daha zarif olduğunu düşünür müsün emin değilim ...


17

Bunu deneyin (global bir değişken olarak veya ihtiyacınız olduğunda somutlaştırın):

<?php
  class Fn {
    public function __call($name, $args) {
      if (function_exists($name)) {
        return call_user_func_array($name, $args);
      }
    }
  }

  $fn = new Fn();
?>

Artık herhangi bir işlev çağrısı $fnörnek üzerinden gider . Böylece mevcut işlev testfunction()bir yorumda çağrılabilir.{$fn->testfunction()}

Temel olarak, tüm işlevleri bir sınıf örneğine sarıyoruz __call magicve sınıf yöntemini çağrılması gereken gerçek işlevle eşlemek için PHP'nin yöntemini kullanıyoruz .


2
Bu, mevcut bir projeye sadece şablon oluşturma motoru ekleyemeyeceğiniz zamanlar için iyi bir çözümdür. Teşekkür ederim, şimdi kullanıyorum.
Brandon

performans kritik olduğunda yaygın olarak kullanılmamalıdır: Performansın call_user_func_arrayson kez php.net'teki
Markus

Güzel! Onu seviyorum, neden bunu düşünmedim?!? :-)
MikeSchinkel

11

Tamlık için, !${''} kara büyü ayrıştırıcı hackini de kullanabilirsiniz :

echo <<<EOT
One month ago was ${!${''} = date('Y-m-d H:i:s', strtotime('-1 month'))}.
EOT;

8
Hogwarts'a gittin mi?
Starx

Bu işe yarıyor çünkü false == ''. Adı 0 ( '') olan bir değişken tanımlayın . İstediğiniz değere ayarlayın ( ${''} = date('Y-m-d H:i:s', strtotime('-1 month'))). Negatifleştirin ( !) ve bir değişkene ( ${false}) dönüştürün . falsebir dizeye dönüştürülmesi gerekiyor ve (string)false === ''. Yanlış bir değer yazdırmaya çalışırsanız, bunun yerine hata verecektir. Aşağıdaki dize daha okunamaz olmanın pahasına, truthy ve falsy değerler hem çalışır: "${(${''}=date('Y-m-d H:i:s', strtotime('-1 month')))!=${''}}".
CJ Dennis

Ve eğer yazdırmak istiyorsan NAN kullanın "${(${''} = date('Y-m-d H:i:s', strtotime('-1 month')) )==NAN}".
CJ Dennis

9

Biraz geç kaldım ama rastgele karşılaştım. Gelecekteki okuyucular için muhtemelen yapacağım şey şu:

Ben sadece bir çıktı tamponu kullanırdım. Temel olarak, arabelleğe alma işlemini ob_start () kullanarak başlatırsınız, ardından içinde herhangi bir işlev, değişken vb. Bulunan "şablon dosyanızı" eklersiniz, arabelleğin içeriğini alır ve bunları bir dizeye yazarsınız ve ardından tamponu kapatırsınız. Sonra ihtiyacınız olan herhangi bir değişkeni kullandınız, herhangi bir işlevi çalıştırabilirsiniz ve hala IDE'nizde HTML sözdizimi vurgulamasına sahipsiniz.

Demek istediğim şu:

Şablon Dosyası:

<?php echo "plain text and now a function: " . testfunction(); ?>

Senaryo:

<?php
ob_start();
include "template_file.php";
$output_string = ob_get_contents();
ob_end_clean();
echo $output_string;
?>

Bu yüzden betik, template_file.php'yi arabelleğine dahil eder, herhangi bir işlevi / yöntemi çalıştırır ve yol boyunca herhangi bir değişken atar. Daha sonra tamponun içeriğini bir değişkene kaydedersiniz ve onunla istediğinizi yaparsınız.

Bu şekilde, tam o anda sayfada yankılamak istemezseniz, zorunda kalmazsınız. Çıktısını almadan önce dizeye döngü yapabilir ve eklemeye devam edebilirsiniz.

Şablon motoru kullanmak istemiyorsanız, bunun en iyi yol olduğunu düşünüyorum.


6

Bu kod parçası, değişkenleri userscope içinde tanımladığınız işlevlerin adıyla tanımlar ve bunları aynı adı içeren bir dizeye bağlar. Göstermeme izin verin.

function add ($int) { return $int + 1; }
$f=get_defined_functions();foreach($f[user]as$v){$$v=$v;}

$string = <<< heredoc
plain text and now a function: {$add(1)}
heredoc;

Şimdi çalışacak.


@MichaelMcMillian'ın herhangi bir fonksiyonla aynı isimli değişkenleri olmasa iyi olur, değil mi?
s3c

6

burada sarma işlevi ile güzel bir çözüm bulundu: http://blog.nazdrave.net/?p=626

function heredoc($param) {
    // just return whatever has been passed to us
    return $param;
}

$heredoc = 'heredoc';

$string = <<<HEREDOC
\$heredoc is now a generic function that can be used in all sorts of ways:
Output the result of a function: {$heredoc(date('r'))}
Output the value of a constant: {$heredoc(__FILE__)}
Static methods work just as well: {$heredoc(MyClass::getSomething())}
2 + 2 equals {$heredoc(2+2)}
HEREDOC;

// The same works not only with HEREDOC strings,
// but with double-quoted strings as well:
$string = "{$heredoc(2+2)}";

2
Bundan 2,5 yıl önce tam olarak aynı çözümü önerdim. stackoverflow.com/a/10713298/1166898
CJ Dennis

5

Heredoc kullanmanın HTML kodu oluşturmak için harika olduğunu düşünüyorum. Örneğin, aşağıdakileri neredeyse tamamen okunamaz buluyorum.

<html>
<head>
  <title><?php echo $page_title; ?></title>
</head>
<body>
  <?php echo getPageContent(); ?>
</body>

Ancak, basitliği elde etmek için başlamadan önce işlevleri değerlendirmek zorunda kalırsınız. Bunun o kadar korkunç bir kısıtlama olduğuna inanmıyorum, çünkü bunu yaparken, hesaplamanızı ekrandan ayırırsınız, ki bu genellikle iyi bir fikirdir.

Aşağıdakilerin oldukça okunabilir olduğunu düşünüyorum:

$page_content = getPageContent();

print <<<END
<html>
<head>
  <title>$page_title</title>
</head>
<body>
$page_content
</body>
END;

Maalesef, sorunuzda işlevi bir değişkene bağlamak iyi bir öneri olmasına rağmen, sonunda, koda değmeyen bir karmaşıklık düzeyi ekler ve kodu daha az okunabilir hale getirir. heredoc'un en büyük avantajı.


2
Son 4 yıl, diğer yaklaşımların çoğundan çok daha akıllı olduğunu kanıtladı. Şablonlarınızda kompozisyon kullanmak (daha küçük sayfalardan oluşan büyük bir sayfa oluşturmak) ve tüm kontrol mantığını ayrı tutmak, şablon oluşturma konusunda ciddi olan herkes için standart yaklaşımdır: facebook'un ReactJS'si bunun için mükemmeldir (XHP'de olduğu gibi), XSLT'de olduğu gibi Sevmiyorum ama akademik olarak sağlam). Yapacağım tek biçimsel notlar: {} 'ı her zaman, temelde okunabilirlikte tutarlılık sağlamak ve daha sonra kazaları önlemek için, değişkenlerimin etrafında kullanırım. Ayrıca, kullanıcılardan gelen verileri htmlspecialchars () yapmayı da unutmayın.
Qaribou'dan Josh

4

Smarty'ye bir bakarım Ben başka olanları kendim denemedim, ama iyi beni çıkarmış - Bir şablon motoru olarak.

Eğer mevcut yaklaşım ile sopa istiyorsa sans şablonları, çıkış tamponlama hakkında kötü nedir? Çağırmak istediğiniz işlevlerin dize isimleri olan değişkenleri bildirmekten çok daha fazla esneklik sağlayacaktır.


3

lambda işlevini unutuyorsunuz:

$or=function($c,$t,$f){return$c?$t:$f;};
echo <<<TRUEFALSE
    The best color ever is {$or(rand(0,1),'green','black')}
TRUEFALSE;

Ayrıca create_function işlevini de kullanabilirsiniz.



2

İşte @CJDennis önerisini kullanan güzel bir örnek:

function double($i)
{ return $i*2; }

function triple($i)
{ return $i*3;}

$tab = 'double';
echo "{$tab(5)} is $tab 5<br>";

$tab = 'triple';
echo "{$tab(5)} is $tab 5<br>";

Örneğin, HEREDOC sözdiziminin iyi bir kullanımı, bir Veritabanında ana-ayrıntı ilişkisine sahip devasa formlar oluşturmaktır. HEREDOC özelliği, her alan adından sonra bir sonek ekleyerek bir FOR kontrolünde kullanılabilir. Bu tipik bir sunucu tarafı görevidir.


2

Bugün php 7.x üzerinde biraz daha şık

<?php

$test = function(){
    return 'it works!';
};


echo <<<HEREDOC
this is a test: {$test()}
HEREDOC;


1
<div><?=<<<heredoc
Use heredoc and functions in ONE statement.
Show lower case ABC="
heredoc
. strtolower('ABC') . <<<heredoc
".  And that is it!
heredoc
?></div>

0
<?php
echo <<<ETO
<h1>Hellow ETO</h1>
ETO;

Onu denemelisin . ETO bittikten sonra; komut girmelisiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.