Предоставление PHP родительской переменной include () для файлов - PullRequest
9 голосов
/ 06 февраля 2010

Есть ли способ, чтобы включенный файл использовался в родительской области, к которой он был вызван? Следующий пример упрощен, но выполняет ту же работу.

По сути, файл будет включен функцией, но он хотел бы, чтобы область действия включаемого файла была областью, откуда была вызвана функция, включившая его.

main.php:

<?php
  if(!function_exists('myPlugin'))
  {
    function myPlugin($file)
      {
        if(file_exists($file)
        {
          require $file;
          return true;
        }
        return false;
      }
  }

  $myVar = 'something bar foo';

  $success = myPlugin('included.php');

  if($success)
  {
    echo $myResult;
  }

included.php:

<?php
  $myResult = strlen($myVar);

Заранее спасибо,
Александр.

РЕДАКТИРОВАТЬ: Решение

Ну, вроде как, благодаря вкладу Chacha102.
Теперь можно вызывать и из класса!

main.php

<?php
  class front_controller extends controller
  {
    public function index_page()
    {
      $myVar = 'hello!';

      // This is the bit that makes it work.
      // I know, wrapping it in an extract() is ugly,
      // and the amount of parameters that you can't change...
      extract(load_file('included.php', get_defined_vars(), $this));

      var_dump($myResult);
    }
    public function get_something()
    {
      return 'foo bar';
    }
  }

  function load_file($_file, $vars = array(), &$c = null)
  {
    if(!file_exists($_file))
    {
      return false;
    }
    if(is_array($vars))
    {
      unset($vars['c'], $vars['_file']);
      extract($vars);
    }
    require $_file;
    return get_defined_vars();
  }

included.php:

<?php
  $myResult = array(
    $myVar,
    $c->get_something()
  );

Если вы хотите сослаться на метод, он должен быть публичным, но результат будет таким, как ожидалось:

array(2) {
  [0]=>
  string(6) "hello!"
  [1]=>
  string(7) "foo bar"
}

Так вот, это на самом деле не имеет никакого практического применения, и единственная причина, по которой я хотел знать, как это сделать, заключается в том, что я упрям. Эта мысль пришла мне в голову и не позволила бы мне победить: D

<rant>
Спасибо всем, кто внес свой вклад. За исключением человека, который меня обвинил. Это был достаточно простой вопрос, и теперь мы выяснили, что (сложное) решение существует.
Винт, "соответствует ли это PHP-образу действий". Когда-нибудь говорили клиенту: «О нет, мы не должны этого делать, это не правильный способ делать вещи!»? Мысль нет.
</rant>

Еще раз спасибо Chacha102:)

Ответы [ 2 ]

4 голосов
/ 06 февраля 2010
function include_use_scope($file, $defined_variables)
{
    extract($defined_variables);
    include($file);
}

include_use_scope("file.php", get_defined_vars());

get_defined_vars() получает ВСЕ переменные, определенные в области, в которой он вызывается. extract() принимает массив и определяет их как локальные переменные.

extract(array("test"=>"hello"));
echo $test; // hello

$vars = get_defined_vars();
echo $vars['test']; //hello

Таким образом, желаемый результат достигнут. Вы можете удалить суперглобальные переменные и прочее из переменных, так как их перезапись может быть плохой.

Ознакомьтесь с этим комментарием для удаления плохих.

Чтобы получить обратное, вы можете сделать что-то вроде этого:

function include_use_scope($file, $defined_variables)
{
    extract($defined_variables);
    return include($file);
}

extract(include_use_scope("file.php", get_defined_vars()));

include.php

// do stuff
return get_defined_vars();

Но в целом, я не думаю, что вы получите желаемый эффект, так как это было не так, как был построен PHP.

0 голосов
/ 06 февраля 2010

Единственный способ, которым я знаю, - это использовать суперглобальный массив.

main.php:

  $GLOBALS['myVar'] = 'something bar foo';

  $success = myPlugin('included.php');

  if($success)
  {
    echo $GLOBALS['myResult'];
  }

included.php:

<?php
  $GLOBALS['myResult'] = strlen($GLOBALS['myVar']);
...