Gọi các hàm PHP trong chuỗi HEREDOC


91

Trong PHP, khai báo chuỗi HEREDOC thực sự hữu ích để xuất ra một khối html. Bạn có thể phân tích cú pháp trong các biến chỉ bằng cách đặt tiền tố cho chúng bằng $, nhưng đối với cú pháp phức tạp hơn (như $ var [2] [3]), bạn phải đặt biểu thức của mình bên trong dấu ngoặc nhọn {}.

Trong PHP 5, nó có thể thực hiện cuộc gọi chức năng trong {} niềng răng bên trong một chuỗi HEREDOC, nhưng bạn phải đi qua một chút về công việc. Bản thân tên hàm phải được lưu trữ trong một biến và bạn phải gọi nó giống như một hàm có tên động. Ví dụ:

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

Như bạn có thể thấy, điều này hơi lộn xộn hơn là chỉ:

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

Có những cách khác ngoài ví dụ mã đầu tiên, chẳng hạn như thoát ra khỏi HEREDOC để gọi hàm hoặc đảo ngược vấn đề và thực hiện điều gì đó như:

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

Cái sau có nhược điểm là đầu ra được đưa trực tiếp vào luồng đầu ra (trừ khi tôi đang sử dụng bộ đệm đầu ra), điều này có thể không như tôi muốn.

Vì vậy, bản chất của câu hỏi của tôi là: có cách nào thanh lịch hơn để tiếp cận điều này không?

Chỉnh sửa dựa trên phản hồi: Có vẻ như một loại công cụ mẫu nào đó sẽ giúp cuộc sống của tôi dễ dàng hơn nhiều, nhưng về cơ bản nó sẽ yêu cầu tôi đảo ngược phong cách PHP thông thường của mình. Đó không phải là điều xấu, nhưng nó giải thích cho sức ì của tôi .. Mặc dù vậy, tôi đang cố gắng tìm ra cách để làm cho cuộc sống dễ dàng hơn, vì vậy tôi đang xem xét các khuôn mẫu.


3
Đây không hoàn toàn là câu trả lời cho câu hỏi của bạn, nhưng do sự hỗ trợ kém cho các lệnh gọi hàm trong câu lệnh heredoc, tôi thường chỉ tạo các chuỗi tôi cần trước khi in heredoc. Sau đó, tôi có thể đơn giản sử dụng một cái gì đó như Text {$string1} Text {$string2} Texttrong heredoc.
rinogo

Câu trả lời:


51

Cá nhân tôi sẽ không sử dụng HEREDOC cho việc này. Nó chỉ không tạo nên một hệ thống "xây dựng khuôn mẫu" tốt. Tất cả HTML của bạn bị khóa trong một chuỗi có một số nhược điểm

  • Không có tùy chọn nào cho WYSIWYG
  • Không có mã hoàn thành cho HTML từ IDE
  • Đầu ra (HTML) bị khóa đối với các tệp logic
  • Cuối cùng, bạn phải sử dụng các bản hack giống như những gì bạn đang cố gắng làm bây giờ để đạt được các mẫu phức tạp hơn, chẳng hạn như lặp

Nhận một công cụ mẫu cơ bản hoặc chỉ sử dụng PHP với bao gồm - đó là lý do tại sao ngôn ngữ có dấu <?php?>phân cách.

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
Có một cách viết tắt cho tiếng vang: <?=$valueToEcho;?>hoặc <%=$valueToEcho;%>phụ thuộc vào cài đặt INI của bạn.
Peter Bailey

3
Hầu hết mọi thứ tôi đã đọc về việc sử dụng các phím tắt đó đều nói rằng sử dụng chúng là một cách thực hành không tốt, và tôi đồng ý. Vì vậy, thật không may nếu bạn đang viết mã cho phân phối, bạn không thể phụ thuộc vào các cài đặt INI đó, do đó việc PHP "hỗ trợ" cho họ tranh luận về mã phân phối. FWIW, tôi đã phải sửa lỗi trong các plugin WordPress của người khác nhiều lần vì họ đã sử dụng các shorthands này.
MikeSchinkel

1
Không, tôi không nói rằng thật tiếc khi phải gõ 7 ký tự; bạn xác định sai vấn đề của tôi. Đó không phải là cách tôi quan tâm, mà là cách đọc . Những ký tự đó tạo ra nhiều nhiễu trực quan khiến việc quét mã nguồn và hiểu mã đang làm khó hơn nhiều. Đối với tôi ít nhất là là NHIÊU dễ dàng hơn để đọc một HEREDOC. (Và BTW, đó là thời gian 7 ký tự bao nhiêu lần nó được sử dụng trong một đoạn HTML nhất định. Nhưng tôi lạc đề.)
MikeSchinkel

12
Ngắn gọn đẹp hơn, sạch hơn và dễ đọc hơn. Trong quan điểm của bạn <?=$title?>nhiều đẹp hơn <? Php echo $ title; ?>. Nhược điểm là, có, để phân phối, rất nhiều ini bị tắt các thẻ ngắn. Nhưng , đoán xem ?? Kể từ PHP 5.4 , các thẻ ngắn được kích hoạt trong PHP bất kể cài đặt ini! Vì vậy, nếu bạn đang viết mã với yêu cầu 5,4+ (ví dụ: giả sử bạn đang sử dụng các đặc điểm), hãy tiếp tục và sử dụng những thẻ ngắn tuyệt vời đó !!
Jimbo

2
Nhân tiện, <? = $ Blah?> Được bật trong 5.4 theo mặc định, ngay cả khi các thẻ ngắn bị tắt.
callmetwan

72

Nếu bạn thực sự muốn làm điều này nhưng đơn giản hơn một chút so với sử dụng một lớp, bạn có thể sử dụng:

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

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

@CJDennis tuyệt vời! Đó là giải pháp tốt nhất và sạch nhất để sử dụng các hàm call bên trong HEREDOC. Có một nguồn lực tốt trong một số tình huống. Trong trang web của tôi, tôi sử dụng HEREDOC để tạo các biểu mẫu với 22 dòng tập trường (khối HEREDOC bên trong vòng lặp FOR), với lệnh gọi hàm để tạo vị trí tabindex.
Paulo Buchsbaum

Bạn thậm chí có thể làm điều này:$my_string = "Half the number of seconds since the Unix Epoch: {$fn(time() / 2 . ' Yes! Really!')}";
CJ Dennis

2
một định nghĩa nhỏ gọn hơn: $fn = function fn($data) { return $data; };
devsmt

1
@devsmt Bạn nói đúng. Và thậm chí ngắn hơn là:$fn = function ($data) { return $data; };
CJ Dennis

ồ, godegolf? được rồi, hãy để tôi tham gia: $fn=function($data){return $data;};rhis nên là ngắn nhất
tôi 1

42

Tôi sẽ làm như sau:

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

Không chắc bạn có coi điều này là thanh lịch hơn không ...


17

Hãy thử điều này (dưới dạng một biến toàn cục hoặc được khởi tạo khi bạn cần):

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

  $fn = new Fn();
?>

Bây giờ bất kỳ lệnh gọi hàm nào cũng đi qua $fnphiên bản. Vì vậy, chức năng hiện cótestfunction() có có thể được gọi trong một heredoc với{$fn->testfunction()}

Về cơ bản, chúng ta đang gói tất cả các hàm vào một cá thể lớp và sử dụng __call magicphương thức của PHP để ánh xạ phương thức lớp với hàm thực cần được gọi.


2
Đây là một giải pháp tốt cho những lúc bạn không thể chỉ thêm một công cụ tạo khuôn mẫu vào một dự án hiện có. Cảm ơn bạn, tôi đang sử dụng nó bây giờ.
Brandon

không nên được sử dụng rộng rãi khi hiệu suất là quan trọng: Tôi đã đọc nhiều lần hiệu suất kém hơn call_user_func_array, lần cuối cùng trong các nhận xét tại php.net: php.net/manual/en/ Chức năng.call-user-func-array.php # 97473
Markus

Đẹp! Tôi yêu nó, tại sao tôi không nghĩ đến điều này?!? :-)
MikeSchinkel

10

Để hoàn chỉnh, bạn cũng có thể sử dụng hack phân tích cú pháp !${''} ma thuật đen :

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

7
Bạn đã đến trường Hogwarts?
Starx

Điều này hoạt động bởi vì false == ''. Định nghĩa một biến có tên có độ dài 0 ( ''). Đặt nó thành giá trị bạn muốn ( ${''} = date('Y-m-d H:i:s', strtotime('-1 month'))). Phủ nhận nó ( !) và chuyển nó thành một biến ( ${false}). falsecần được chuyển đổi thành một chuỗi và (string)false === ''. Nếu bạn cố gắng in một giá trị giả, nó sẽ bị lỗi. Chuỗi sau hoạt động trên cả truthy và giá trị falsy, tại các chi phí của việc thậm chí không thể đọc được nhiều hơn: "${(${''}=date('Y-m-d H:i:s', strtotime('-1 month')))!=${''}}".
CJ Dennis

Và nếu bạn cũng muốn in NAN, hãy sử dụng "${(${''} = date('Y-m-d H:i:s', strtotime('-1 month')) )==NAN}".
CJ Dennis

9

Tôi hơi muộn, nhưng tôi ngẫu nhiên xem được. Đối với bất kỳ độc giả nào trong tương lai, đây là những gì tôi có thể sẽ làm:

Tôi sẽ chỉ sử dụng một bộ đệm đầu ra. Vì vậy, về cơ bản, bạn bắt đầu bộ đệm bằng cách sử dụng ob_start (), sau đó bao gồm "tệp mẫu" của bạn với bất kỳ hàm, biến, v.v. nào bên trong nó, lấy nội dung của bộ đệm và ghi chúng vào một chuỗi, sau đó đóng bộ đệm. Sau đó, bạn đã sử dụng bất kỳ biến nào bạn cần, bạn có thể chạy bất kỳ hàm nào và bạn vẫn có đánh dấu cú pháp HTML có sẵn trong IDE của mình.

Đây là ý tôi:

Tệp mẫu:

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

Kịch bản:

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

Vì vậy, tập lệnh bao gồm template_file.php vào bộ đệm của nó, chạy bất kỳ hàm / phương thức nào và gán bất kỳ biến nào trong quá trình thực hiện. Sau đó, bạn chỉ cần ghi lại nội dung của bộ đệm vào một biến và làm những gì bạn muốn với nó.

Bằng cách đó, nếu bạn không muốn lặp lại nó trên trang ngay tại giây đó, bạn không cần phải làm như vậy. Bạn có thể lặp lại và tiếp tục thêm vào chuỗi trước khi xuất ra.

Tôi nghĩ đó là cách tốt nhất nếu bạn không muốn sử dụng động cơ tạo khuôn mẫu.


6

Đoạn mã này sẽ xác định các biến với tên của các hàm đã xác định của bạn trong userscope và liên kết chúng với một chuỗi có cùng tên. Hãy để tôi chứng minh.

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;

Bây giờ sẽ hoạt động.


@MichaelMcMillian tốt hơn là không có bất kỳ biến nào có tên giống với bất kỳ hàm nào sau đó, phải không?
s3c

6

tìm thấy giải pháp tốt với chức năng gói ở đây: 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
Tôi đã đề xuất chính xác cùng một giải pháp 2,5 năm trước đây. stackoverflow.com/a/10713298/1166898
CJ Dennis

5

Tôi nghĩ rằng việc sử dụng heredoc là rất tốt để tạo mã HTML. Ví dụ, tôi thấy phần sau gần như hoàn toàn không thể đọc được.

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

Tuy nhiên, để đạt được sự đơn giản, bạn buộc phải đánh giá các chức năng trước khi bắt đầu. Tôi không tin đó là một hạn chế khủng khiếp như vậy, vì khi làm như vậy, bạn sẽ tách việc tính toán của mình khỏi hiển thị, đây thường là một ý kiến ​​hay.

Tôi nghĩ những điều sau đây khá dễ đọc:

$page_content = getPageContent();

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

Thật không may, mặc dù đó là một gợi ý tốt mà bạn đã đưa ra trong câu hỏi của mình để liên kết hàm với một biến, nhưng cuối cùng, nó sẽ làm tăng thêm mức độ phức tạp cho mã, điều này không có giá trị và làm cho mã khó đọc hơn, đó là lợi thế chính của heredoc.


2
4 năm qua đã chứng minh điều này thông minh hơn nhiều so với hầu hết các cách tiếp cận khác. Sử dụng bố cục trong các mẫu của bạn (xây dựng một trang lớn bao gồm các trang nhỏ hơn) và giữ tất cả logic điều khiển riêng biệt là cách tiếp cận tiêu chuẩn cho bất kỳ ai nghiêm túc về tạo mẫu: ReactJS của facebook là tuyệt vời cho điều này (XHP), cũng như XSLT (mà Tôi không yêu, nhưng rất thích học thuật). Lưu ý về phong cách duy nhất mà tôi muốn thực hiện: Tôi luôn sử dụng {} xung quanh các vars của mình, chủ yếu để tạo sự nhất quán về khả năng đọc và tránh các tai nạn sau này. Ngoài ra, đừng quên htmlspecialchars () bất kỳ dữ liệu nào đến từ người dùng.
Josh từ Qaribou 14/09/15

4

Tôi sẽ xem qua Smarty như một công cụ mẫu - tôi chưa tự mình thử bất kỳ công cụ nào khác, nhưng nó đã làm tôi rất tốt.

Nếu bạn muốn gắn bó với các mẫu không có phương pháp tiếp cận hiện tại của mình , thì việc đệm đầu ra có gì tệ? Nó sẽ cung cấp cho bạn sự linh hoạt hơn nhiều so với việc phải khai báo các biến là tên chuỗi của các hàm bạn muốn gọi.


3

bạn đang quên về hàm lambda:

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

Bạn cũng có thể sử dụng hàm create_ functions



2

Dưới đây là một ví dụ hay bằng cách sử dụng đề xuất @CJDennis:

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

Ví dụ, một cách sử dụng tốt cho cú pháp HEREDOC là tạo ra các biểu mẫu lớn với mối quan hệ tổng thể-chi tiết trong Cơ sở dữ liệu. Người ta có thể sử dụng tính năng HEREDOC bên trong điều khiển FOR, thêm hậu tố sau mỗi tên trường. Đó là một nhiệm vụ phía máy chủ điển hình.



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;

bạn nên thử nó . sau khi kết thúc ETO; lệnh bạn nên nhập.


0

Hôm nay nó thanh lịch hơn một chút trên php 7.x

<?php

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


echo <<<HEREDOC
this is a test: {$test()}
HEREDOC;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.