โครงสร้างระบบแม่แบบโดยใช้ PHP ธรรมดาได้อย่างไร


15

ฉันอ่านคำถามนี้ไปที่ stackoverflow:

/programming/104516/calling-php-functions-within-heredoc-strings

และคำตอบที่ได้รับการยอมรับบอกว่าจะทำแม่แบบ PHP ธรรมดาดังนี้:

template.php:

<html>
    <head>
        <title> <? = $ ชื่อ?> </ title>
    </ head>
    <body>
        <? = getContent ()?>
    </ body>
</ html>

index.php:

<php?

$ title = 'ชื่อการสาธิต';

ฟังก์ชัน getContent () {
    ส่งคืน '<p> Hello World! </p>';
}

รวมถึง ( 'template.php');

?>

สำหรับฉันข้างต้นไม่ได้มีโครงสร้างที่ดีในแง่ที่ template.php ขึ้นอยู่กับตัวแปรที่กำหนดไว้ในสคริปต์อื่น ๆ และคุณใช้การรวม () เพื่อเรียกใช้รหัสเมื่อคุณทำinclude('template.php')(ต่างจากการใช้การรวม () เพื่อรวมคลาสหรือฟังก์ชันที่ไม่ได้ดำเนินการทันที)

ฉันรู้สึกว่าวิธีที่ดีกว่าคือการห่อเทมเพลตของคุณไว้ในฟังก์ชัน:

template.php:

<php?

ฟังก์ชั่นเทมเพลต ($ title, $ content) {
    ob_start (); ?>

<html>
    <head>
        <title> <? = $ ชื่อ?> </ title>
    </ head>
    <body>
        <? = เนื้อหา $?>
    </ body>
</ html>

    <? php return ob_get_clean ();
}

?>

index.php:

<php?

require_once ( 'template.php');

เทมเพลตพิมพ์ ('ชื่อตัวอย่าง', '<p> Hello World! </p>');

?>

วิธีที่สองดีกว่าไหม? มีวิธีที่ดีกว่านี้อีกหรือไม่

คำตอบ:


12

ฉันจะไม่ทำวิธีที่สองเนื่องจากไม่มีการตั้งชื่อพารามิเตอร์

บทความที่เขียนอย่างดีเกี่ยวกับการอธิบายว่าระบบเทมเพลตควรทำงานอย่างไรมาจาก Parr ซึ่งมักจะถูกยกมาโดยผู้เขียนระบบแม่แบบและ / หรือกรอบงาน web-mvc

โดยส่วนตัวแล้วสิ่งที่ฉันมักจะชอบที่จะใช้ชั้น ArrayObject กับอาร์เรย์คุณสมบัติและแม่แบบจะอ้างถึงซึ่งในความเป็นจริงจะเป็นแม่แบบของวัตถุ$this->propertyName $this->property['name']สิ่งนี้สามารถทำได้โดยการใช้__setและ__getดังนั้น:

class Template {
  private $_scriptPath=TEMPLATE_PATH;//comes from config.php
  public $properties;
  public function setScriptPath($scriptPath){
    $this->_scriptPath=$scriptPath;
  }
  public function __construct(){
      $this->properties = array();
  }
  public function render($filename){

   ob_start();
   if(file_exists($this->_scriptPath.$filename)){
     include($this->_scriptPath.$filename);
    } else throw new TemplateNotFoundException();
    return ob_get_clean();
  }
  public function __set($k, $v){
      $this->properties[$k] = $v;
  }
  public function __get($k){
      return $this->properties[$k];
  }
}

และแม่แบบจะมีลักษณะดังนี้:

<html>
      <head>
         <title><?=$this->title?></title>
      </head>
      <body>Hey <?=$this->name?></body>
</html>

และกล่าวอ้างว่ามันจะมีลักษณะ:

$view = new Template();
$view->title="Hello World app";
$view->properties['name'] = "Jude";
echo $view->render('hello.inc');

เท่าที่ฉันจำได้นี่คือลักษณะของ Symfony 1.x และเครื่องมือเท็มเพลต Zend_View แบบเก่าและสำหรับฉันมันก็ใช้ได้


TinyButStrongทำสิ่งที่คล้ายกันเช่นกัน
Izkata

คุณจะจัดการกับการวนลูปมากกว่าบางคะแนนว่าอย่างไร คุณใช้แม่แบบ "sub" แยกต่างหากหรือไม่
Ryan

ฉันสงสัยว่ามีวิธีใดที่จะกำจัดการใช้ $ this ในเทมเพลตตัวอย่างเช่นแค่ $ title หรือ $ name
Ryan

1
@Ryan คุณสามารถใช้extract($this->properties);เพื่อแยกคุณสมบัติออกเป็นตัวแปรได้ก่อนคำสั่ง include
จอยซ์บาบู

1

เทมเพลตจะขึ้นอยู่กับตัวแปรภายนอกเสมอและด้วย PHP ที่เป็นภาษาไดนามิกจึงไม่มีวิธีการบังคับใช้ในเวลารวบรวมที่จะมี ดังนั้นวิธีแรกอาจจะใช้ได้ ยังคงมีปัญหาเล็กน้อยที่:

  • ตัวอย่างไม่สนใจการเข้ารหัส HTML ซึ่งหมายความว่าคุณมีช่องโหว่ XSS
  • หากไม่ได้ตั้งค่าตัวแปรตัวใดตัวหนึ่งรหัสจะเพิ่มการเตือน คุณจะไม่เห็นว่าคำเตือนเหมาะสมหรือไม่ (อาจเป็นตัวแปรเสริม)

วิธีการตรงไปตรงมามากคือการเขียนฟังก์ชั่นโดยเฉพาะอย่างยิ่งที่มีชื่อสั้น ๆ ที่จะดูแลทั้งสองนี้ เรียกมัน_()ดูเหมือนว่าจะมีการประชุมร่วมกัน รุ่นที่เรียบง่ายอาจมีลักษณะเช่นนี้:

function _($raw) {
    if (isset($raw)) {
        return htmlspecialchars($raw);
    }
}

จากนั้นในเทมเพลตของคุณคุณต้องทำ:

<title><?= _($title) ?></title>

สิ่งอื่น ๆ ที่เกี่ยวข้องกับ_()ฟังก์ชั่น:

  • ระบุอาร์กิวเมนต์ที่สองเพื่ออนุญาตให้มีการแทนที่การhtmlspecialcharsโทรสำหรับกรณีที่คุณต้องการส่ง HTML ลงในมันแทนที่จะเป็นสตริงดิบ
  • เพิ่มการตรวจสอบชนิดเพื่อให้อาร์เรย์และวัตถุจะไม่ให้ผลArrayและObjectแต่เป็นสิ่งที่มีความหมาย (หรือสตริงว่าง)
  • เพิ่มการสนับสนุนสากล (ยังเป็นข้อโต้แย้งอื่น)
  • เมื่ออยู่ในโหมดดีบักให้พิมพ์ชื่อของตัวแปรด้วยการจัดรูปแบบพิเศษบางอย่างหากไม่ได้กำหนดไว้ ด้วยวิธีนี้คุณสามารถดูข้อมูลคร่าวๆได้ว่ามีอะไรผิดปกติกับเทมเพลตหรือไม่

1

สิ่งแรกtemplate.phpนั้นง่ายต่อการโหลดตามที่เป็นในDreamweaver / bluegriffon / อะไรก็ตามและแก้ไขโดยนักออกแบบเว็บไซต์ที่ไม่เข้าใจเซิร์ฟเวอร์ฝั่งที่สอง ... มันก็ยังทำได้ดีกว่า .

ฉันจะไปกับคนแรกเพื่อให้ดูเหมือนHTML ที่มีประโยชน์วิธีที่นักออกแบบบุคคลที่สามมักจะชอบ


ในสิ่งที่รู้สึก? คุณหมายความว่าไม่สามารถเปลี่ยนแปลงได้โดยใช้การลากและวาง ข้อความที่สองนั้นเหมือนกันกับตัวแรก แต่ด้วยสองบรรทัดของ PHP ที่ล้อมรอบ ดังนั้นสมมติว่ามันจะมีโครงสร้างนั้นเสมอมันไม่ได้ยากสำหรับพวกเขาที่จะแก้ไขด้วยมือ
Ryan

1
เทมเพลตที่ดีเหมาะสมสำหรับนักพัฒนาเทมเพลตที่ดีเหมาะสมสำหรับนักออกแบบ
Citricguy

1

เนื่องจาก Codeigniter เป็นกรอบงานที่ฉันชอบฉันขอเสนอวิธีแก้ปัญหา Codeigniter-ish ให้คุณ:

class Template {
    protected $path, $data;

    public function __construct($path, $data = array()) {
        $this->path = $path;
        $this->data = $data;
    }

    public function render() {
        if(file_exists($this->path)){
            //Extracts vars to current view scope
            extract($this->data);

            //Starts output buffering
            ob_start();

            //Includes contents
            include $this->path;
            $buffer = ob_get_contents();
            @ob_end_clean();

            //Returns output buffer
            return $buffer;
        } else {
            //Throws exception
        }
    }       
}

เทมเพลตของคุณจะมีลักษณะดังนี้:

<html>
    <head>
        <title><?=$title?></title>
    </head>
    <body>
        <?=$content?>
    </body>
</html>

และคุณจะสร้างมันขึ้นมาโดยการยกคลาสให้ส่งข้อมูลในอาร์เรย์เป็นพารามิเตอร์ตัวสร้างและเรียกเมธอด 'render':

$data = array('title' => 'My title', 'content' => 'My content');
$tmpl = new Template('template.php', $data);
echo $tmpl->render();

ด้วยวิธีนี้คุณจะไม่เรียกใช้งานโค้ดที่รวมโดยตรงและคุณยังสามารถอ่านเทมเพลตของคุณได้ดังนั้นนักออกแบบจะมีความสุข


-3

Php ไม่ใช่ภาษาโปรแกรม ดังนั้นการเขียนอย่างมากจึงเป็นไปไม่ได้หากภาษาของคุณไม่มีระบบการพิมพ์จริง แต่คุณสามารถช่วย IDE ของคุณอย่าง PHP-Storm ทำเคล็ดลับที่คุณต้องการ ...

นิยามมุมมองของคุณ:

interface mySimpleView { 
  public function getTitle(); 
} 

ไฟล์เทมเพลตของคุณ:

<?php
/**
* @var $this mySimpleView  <== Your IDE will try to use this type.
*/
?>

<h1><?= $this->getTitle() ?></h1>
<p><?= $this->getContent() ?></p> <!-- <= IDE will warn you !  -->
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.