web-dev-qa-db-fra.com

Est-il possible d'écraser une fonction dans PHP

Pouvez-vous déclarer une fonction comme celle-ci ...

function ihatefooexamples(){
  return "boo-foo!";
};

Et puis redeclare un peu comme ça ...

if ($_GET['foolevel'] == 10){
  function ihatefooexamples(){
    return "really boo-foo";
  };
};

Est-il possible d'écraser une fonction de cette façon?

En tous cas?

57
Mark Lalor

Modifier

Pour adresser des commentaires que cette réponse ne traite pas directement le question originale. Si vous venez d'une recherche Google, commencez ici

Il existe une fonction appelée override_function qui correspond réellement à la facture. Cependant, étant donné que cette fonction fait partie de Le débogueur PHP avancé extension, il est difficile de dire que override_function() est destiné à une utilisation en production. Par conséquent, je dirais "Non", il n'est pas possible d'écraser une fonction avec l'intention que le questionneur initial avait en tête.

Réponse originale

C'est là que vous devriez tirer parti de la POO, en particulier du polymorphisme.

interface Fooable
{
    public function ihatefooexamples();
}

class Foo implements Fooable
{
    public function ihatefooexamples()
    {
        return "boo-foo!";
    }
}

class FooBar implements Fooable
{
    public function ihatefooexamples()
    {
        return "really boo-foo";
    }
}

$foo = new Foo();

if (10 == $_GET['foolevel']) {
    $foo = new FooBar();
}

echo $foo->ihatefooexamples();
89
Peter Bailey

Patch de singe dans l'espace de noms php> = 5.3

Le patch de singe est une méthode moins évasive que de modifier l’interprète.

La correction de singe est l'art de remplacer la mise en oeuvre réelle par un "correctif" similaire. 

Compétences Ninja

Avant de pouvoir utiliser les correctifs comme un Ninja PHP, nous devons d'abord comprendre les espaces de noms PHP.

Depuis PHP 5.3, nous avons été initiés aux espaces de noms que vous pourriez peut-être reconnaître à première vue comme équivalents à quelque chose comme les paquets Java, mais ce n'est pas tout à fait pareil. Les espaces de noms, en PHP, permettent d'encapsuler la portée en créant une hiérarchie de focus, en particulier pour les fonctions et les constantes. Comme ce sujet, repli sur des fonctions globales , vise à expliquer.

Si vous ne fournissez pas d'espace de nom lorsque vous appelez une fonction, PHP commence par rechercher dans l'espace de nom actuel, puis descend dans la hiérarchie jusqu'à ce qu'il trouve la première fonction déclarée dans cet espace de nom préfixé et l'exécute. Par exemple, si vous appelez print_r(); à partir de namespace My\Awesome\Namespace;, ce que PHP fait, commence par rechercher une fonction appelée My\Awesome\Namespace\print_r(); puis My\Awesome\print_r(); puis My\print_r(); jusqu'à ce qu'il trouve la fonction intégrée PHP dans l'espace de noms global \print_r();.

Vous ne pourrez pas définir une function print_r($object) {} dans l'espace de noms global, car cela entraînera une collision de noms, car une fonction portant ce nom existe déjà.

Attendez-vous à une erreur fatale de la part de:

Fatal error: Cannot redeclare print_r()

Mais rien ne vous empêche cependant de faire cela dans le cadre d'un espace de noms.

Patcher le singe

Supposons que vous ayez un script utilisant plusieurs appels print_r();.

Exemple:

<?php
     print_r($some_object);
     // do some stuff
     print_r($another_object);
     // do some other stuff
     print_r($data_object);
     // do more stuff
     print_r($debug_object);

Mais vous changez d'avis par la suite et vous souhaitez plutôt que la sortie soit enveloppée dans des balises <pre></pre>. Vous est-il déjà arrivé? 

Avant que vous ne changiez chaque appel en print_r();, pensez plutôt à appliquer des correctifs aux singes.

Exemple:

<?php
    namespace MyNamespace {
        function print_r($object) 
        {
            echo "<pre>", \print_r($object, true), "</pre>"; 
        }

        print_r($some_object);
        // do some stuff
        print_r($another_object);
        // do some other stuff
        print_r($data_object);
        // do more stuff
        print_r($debug_object);
    }

Votre script utilisera désormais MyNamespace\print_r(); au lieu de la fonction globale \print_r();

Fonctionne très bien pour se moquer des tests unitaires.

nonJoy!

57
nickl-

Regardez override_function pour remplacer les fonctions.

override_function - Remplace la fonction intégrée les fonctions

Exemple:

override_function('test', '$a,$b', 'echo "DOING TEST"; return $a * $b;');
24
Sarfraz

la réponse courte est non, vous ne pouvez pas écraser une fonction une fois que cela se trouve dans la portée de la fonction PHP.

votre meilleur d'utiliser des fonctions anonymes comme si

$ihatefooexamples = function()
{
  return "boo-foo!";
}

//...
unset($ihatefooexamples);
$ihatefooexamples = function()
{
   return "really boo-foo";
}

http://php.net/manual/en/functions.anonymous.php

13
RobertPitt

Vous ne pouvez redéclarer aucune fonction en PHP. Vous pouvez cependant les remplacer. Vérifiez fonctions prioritaires ainsi que renommer des fonctions afin de sauvegarder la fonction que vous substituez si vous le souhaitez.

Donc, gardez à l'esprit que lorsque vous substituez une fonction, vous la perdez. Vous voudrez peut-être envisager de le garder, mais sous un nom différent. Je dis juste.

De plus, s'il s'agit de fonctions de classes que vous souhaitez remplacer, il vous suffira de créer une sous-classe et de redéclarer la fonction dans votre classe sans avoir à renommer_function et override_function.

Exemple:

rename_function('mysql_connect', 'original_mysql_connect' );
override_function('mysql_connect', '$a,$b', 'echo "DOING MY FUNCTION INSTEAD"; return $a * $b;');
11
tomlikestorock

J'inclurais toutes les fonctions d'un cas dans un fichier include et les autres dans un autre include.

Par exemple, simple.inc contiendrait function boofoo() { simple } et really.inc contiendrait function boofoo() { really }

Cela facilite la lisibilité/la maintenance de votre programme, en ayant toutes les fonctions du même genre dans le même inc.

Puis en haut de votre module principal

  if ($_GET['foolevel'] == 10) {
    include "really.inc";
  }
  else {
    include "simple.inc";
  }
4
Ring Ø

Vous pouvez utiliser l'extension PECL

mais c'est une mauvaise pratique à mon avis. Vous utilisez des fonctions, mais consultez le modèle de conception Decorator . Peut emprunter l'idée de base de celui-ci.

3
Gordon

Non, ce sera un problème. PHP Fonctions de variable

1
Chris

Une solution pour le cas connexe où vous avez un fichier d'inclusion A que vous pouvez modifier et souhaitez remplacer certaines de ses fonctions dans un fichier d'inclusion B (ou le fichier principal):

Fichier principal:

<?php
$Override=true; // An argument used in A.php
include ("A.php");
include ("B.php");
F1();
?>

Inclure le fichier A:

<?php
if (!@$Override) {
   function F1 () {echo "This is F1() in A";}
}
?>

Inclure le fichier B:

<?php
   function F1 () {echo "This is F1() in B";}
?>

Parcourir le fichier principal affiche " Ceci est F1 () dans B ".

1
David Spector

En fonction de la situation où vous en avez besoin, vous pouvez peut-être utiliser des fonctions anonymes telles que:

$greet = function($name)
{
    echo('Hello ' . $name);
};

$greet('World');

... alors vous pouvez définir une nouvelle fonction pour la variable donnée à tout moment

0
esud