web-dev-qa-db-fra.com

Appeler PHP fonctions dans les chaînes HEREDOC

En PHP, les déclarations de chaînes HEREDOC sont vraiment utiles pour sortir un bloc de html. Vous pouvez le faire analyser dans des variables simplement en les préfixant avec $, mais pour une syntaxe plus compliquée (comme $ var [2] [3]), vous devez mettre votre expression entre accolades {}.

En PHP 5, il est possible de faire des appels de fonction entre accolades {} à l'intérieur d'une chaîne HEREDOC, mais vous devez passer par un peu de travail. La fonction le nom lui-même doit être stocké dans une variable, et vous devez l'appeler comme s'il s'agissait d'une fonction nommée dynamiquement. Par exemple:

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

Comme vous pouvez le voir, c'est un peu plus compliqué que simplement:

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

En plus du premier exemple de code, il existe d'autres moyens, tels que sortir du HEREDOC pour appeler la fonction, ou inverser le problème et faire quelque chose comme:

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

Ce dernier a l'inconvénient que la sortie est directement placée dans le flux de sortie (sauf si j'utilise la mise en mémoire tampon de sortie), ce qui n'est peut-être pas ce que je veux.

Donc, l'essence de ma question est: existe-t-il une manière plus élégante d'aborder cela?

Modifier en fonction des réponses: Il semble certainement qu'une sorte de moteur de modèle me rendrait la vie beaucoup plus facile, mais il me faudrait essentiellement inverser mon style PHP. Pas que ce soit une mauvaise chose, mais cela explique mon inertie .. Je suis prêt à trouver des moyens de vous faciliter la vie, alors je cherche des modèles maintenant.

86
Doug Kavendek

Je n'utiliserais pas du tout HEREDOC pour cela, personnellement. Cela ne fait tout simplement pas un bon système de "construction de modèles". Tout votre code HTML est verrouillé dans une chaîne qui présente plusieurs inconvénients

  • Pas d'option pour WYSIWYG
  • Aucune complétion de code pour HTML à partir d'IDE
  • Sortie (HTML) verrouillée sur les fichiers logiques
  • Vous finissez par devoir utiliser des hacks comme ce que vous essayez de faire maintenant pour obtenir des modèles plus complexes, tels que la boucle

Obtenez un moteur de modèle de base, ou utilisez simplement PHP avec des inclusions - c'est pourquoi le langage a le <?php et ?> délimiteurs.

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');
52
Peter Bailey

Si vous voulez vraiment le faire mais un peu plus simple que d'utiliser une classe, vous pouvez utiliser:

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

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

Je ferais ce qui suit:

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

Je ne sais pas si vous considéreriez cela comme plus élégant ...

39
boxxar

Essayez ceci (soit en tant que variable globale, soit instancié lorsque vous en avez besoin):

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

  $fn = new Fn();
?>

Désormais, tout appel de fonction passe par l'instance $fn. Ainsi, la fonction existante testfunction() peut être appelée dans un hérédoc avec {$fn->testfunction()}

Fondamentalement, nous enveloppons toutes les fonctions dans une instance de classe et utilisons la méthode __call magic De PHP pour mapper la méthode de classe à la fonction réelle devant être appelée.

17
Isofarro

Je suis un peu en retard, mais je l'ai rencontré au hasard. Pour tous les futurs lecteurs, voici ce que je ferais probablement:

Je voudrais simplement utiliser un tampon de sortie. Donc, fondamentalement, vous commencez la mise en mémoire tampon à l'aide de ob_start (), puis vous incluez votre "fichier modèle" avec toutes les fonctions, variables, etc. à l'intérieur, obtenez le contenu du tampon et les écrivez dans une chaîne, puis fermez le tampon. Ensuite, vous avez utilisé toutes les variables dont vous avez besoin, vous pouvez exécuter n'importe quelle fonction et vous avez toujours la coloration syntaxique HTML disponible dans votre IDE.

Voici ce que je veux dire:

Fichier modèle:

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

Script:

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

Le script inclut donc le template_file.php dans sa mémoire tampon, exécutant toutes les fonctions/méthodes et affectant toutes les variables en cours de route. Ensuite, vous enregistrez simplement le contenu du tampon dans une variable et faites ce que vous voulez avec.

De cette façon, si vous ne voulez pas l'écho sur la page juste à cette seconde, vous n'êtes pas obligé. Vous pouvez boucler et continuer à ajouter à la chaîne avant de la sortir.

Je pense que c'est la meilleure façon de procéder si vous ne souhaitez pas utiliser un moteur de modèles.

9
BraedenP

Pour être complet, vous pouvez également utiliser le !${''} magie noire piratage de l'analyseur :

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

Je pense que l'utilisation de heredoc est excellente pour générer du code HTML. Par exemple, je trouve ce qui suit presque complètement illisible.

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

Cependant, afin d'atteindre la simplicité, vous êtes obligé d'évaluer les fonctions avant de commencer. Je ne pense pas que ce soit une contrainte aussi terrible, car ce faisant, vous finissez par séparer votre calcul de l'affichage, ce qui est généralement une bonne idée.

Je pense que ce qui suit est assez lisible:

$page_content = getPageContent();

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

Malheureusement, même si c'était une bonne suggestion que vous avez faite dans votre question de lier la fonction à une variable, en fin de compte, cela ajoute un niveau de complexité au code, ce qui ne vaut pas la peine, et rend le code moins lisible, ce qui est le principal avantage de heredoc.

5
MLU

trouvé une belle solution avec une fonction d'emballage ici: 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)}";
5
p.voinov

Cet extrait de code définira des variables avec le nom de vos fonctions définies dans userscope et les liera à une chaîne qui contient le même nom. Laissez-moi vous démontrer.

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;

Fonctionne maintenant.

5
Michael McMillan

Je voudrais jeter un œil à Smarty comme moteur de modèle - je n'en ai pas essayé d'autres moi-même, mais cela m'a bien fait.

Si vous vouliez vous en tenir à votre approche actuelle sans modèles, quel est le problème de la mise en mémoire tampon de sortie? Cela vous donnera beaucoup plus de flexibilité que d'avoir à déclarer des variables qui sont les noms sting des fonctions que vous souhaitez appeler.

4
nickf

Voici un bel exemple utilisant la proposition @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>";

Par exemple, une bonne utilisation de la syntaxe HEREDOC est de générer d'énormes formulaires avec une relation maître-détail dans une base de données. On peut utiliser la fonction HEREDOC à l'intérieur d'un contrôle FOR, en ajoutant un suffixe après chaque nom de champ. C'est une tâche côté serveur typique.

2
Paulo Buchsbaum

Un peu tard mais quand même. C'est possible dans heredoc!

Jetez un œil dans le manuel php, section "Syntaxe complexe (bouclée)"

2
tftd

vous oubliez la fonction lambda:

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

Vous pouvez également utiliser la fonction create_function

2
Ismael Miguel

Les gars doivent noter qu'il fonctionne également avec les chaînes entre guillemets doubles.

http://www.php.net/manual/en/language.types.string.php

Astuce intéressante quand même.

1
SomeOne
<div><?=<<<heredoc
Use heredoc and functions in ONE statement.
Show lower case ABC="
heredoc
. strtolower('ABC') . <<<heredoc
".  And that is it!
heredoc
?></div>
1
Ken
<?php
echo <<<ETO
<h1>Hellow ETO</h1>
ETO;

tu devrais l'essayer . après la fin de l'ETO; vous devez donner une entrée.

0
Rubel Hossain