0

Is there any way to include a PHP file, and be able to read what values global variables and/or class static properties would have in that file’s scope, without polluting those same global variables and static class properties in the calling scope?

Say I have example.php:

$latestExample = null;

class Example {
  public $name;
  public static examples = [];

  public function __construct($name) {
    $this->name = $name;
    self::$examples[] = $this;
    $latestExample = $this;
  }
}

If I use include('example.php'), the $latestExample and Example::$examples will be filled by this file—I don’t want that. Instead, I want to do something where everything from this file is restricted to some other scope, and my own global variables and static class properties are untouched.

Important details about the file I’m “including”

  • They may include things themselves—almost always using require_once.
  • They may explicitly set globals via $GLOBALS, not necessarily just by writing variables in the root scope. That seems to nix this answer.
  • There are zero security concerns here. These are static script files sitting on the server, and there is no user interaction whatsoever.
  • I can modify these files at will, but the point of this exercise is to limit how much I have to. For instance, suggesting that I “simply” rewrite everything to avoid using globals and static class properties in this manner is a non-answer.

The explanation here is that I have an extensive, extremely complicated, custom-written system that leverages global variables and static class properties extensively. Implicitly, the global space is treated as its own “object” that the page is representing. This was a questionable choice when I first made it, years and years ago, but it’s mostly served me fairly well because each page really is devoted to all the details and such of a particular subject. All the variables and objects I was creating were things owned by that subject.

Except now, of course, I have cases where a subject can have sub-subjects, and I want to re-use everything I have for individual subjects for the sub-subjects because they have gotten sufficiently complicated. Problem is, running the scripts to create the sub-subjects will pollute the global variables and static class properties for the primary subject, making the scripts think all of those properties are properties of the main subject, too.

I have tried to look into “sandbox” options for PHP, but most of what I can find is either defunct, or an online tool or environment. This isn’t about security; I don’t need a separate process or anything like that. It’s plausible that some of what I have seen could do the job, but since they’re not geared for that I can’t find guidance on how to use them for that.

For the curious, the system produces a character sheet for a Dungeons & Dragons “v.3.5 revised edition” character. Each page is the sheet for a given character, so the global variables and static class properties are supposed to be stats, abilities, and features of that character. Now I just want to include the stats and properties of another character—a minion—within the same page as the main character. In the past I had just manually created such sections, but now I have a minion who is fully as complex as a full character, and I want to re-use everything I have for creating the sheet of a character for the sake of this minion’s section on the main character’s sheet.

KRyan
  • 7,308
  • 2
  • 40
  • 68
  • 1
    Have you considered using namespaces? – Don't Panic Aug 17 '21 at 21:28
  • 2
    _"Is there any way..."_ No, not without parsing source, and you surely don't want to do that. Most of what you're doing can be fixed with namespaces, but you can't have actual globals be global when you want them to, and then _not_ be global when you don't. – Alex Howansky Aug 17 '21 at 21:34
  • Also note, _"These are static script files sitting on the server, and there is no user interaction whatsoever,"_ doesn't by any stretch indicate a lack of security concerns. Any time you're dealing with overlapping scopes, you have the possibility of poisoning. – Alex Howansky Aug 17 '21 at 21:38
  • @Don'tPanic Pretty sure they won’t help, since the main page and the sub-pages need to use the same classes and globals. – KRyan Aug 17 '21 at 22:27
  • @AlexHowansky I don’t have to worry about poisoning from anyone but myself; none of this code is interacting with anything except other code I wrote. Anyway, what I want is for the included file to be executed entirely in a silo with its own global space, and then be able to peer into that space. Doesn’t sound entirely implausible, though that doesn’t mean that there’s actually a way to do it. – KRyan Aug 17 '21 at 22:30
  • `its own global space`...is an oxymoron. If something is global, it's is global, full stop - therefore it's global everywhere. If you want something to have a separate space, use a namespace. – ADyson Aug 17 '21 at 23:07
  • 1
    `the main page and the sub-pages need to use the same classes and globals`...then they'd both need to reference your namespace. And if you've got widespread use of global functions / variables, that's largely incompatible with a namespaced, OO design anyway, so maybe you actually just need to do some refactoring. You say that's not the answer you want, but unfortunately you seem to be attempting to avoid reality. – ADyson Aug 17 '21 at 23:09
  • `Implicitly, the global space is treated as its own “object” that the page is representing. This was a questionable choice`...unfortunately, yes. And now the chicken is well and truly home to roost. – ADyson Aug 17 '21 at 23:11
  • @Adyson Oh no, refactoring is not my only option—there’s also the option of just giving up on the feature I was planning, which is absolutely what I’m going to do. I appreciate your helping me out with it, though; saves me the trouble of trying to dig through possibly-related ideas and seeing if they’ll work for my use-case. One other thing, though: please don’t abuse code formatting for non-code. Quotation marks work just fine, and misused code formatting can make the site less accessible as it can interfere with some screen readers. – KRyan Aug 18 '21 at 01:46

1 Answers1

0

My solution here was to create a version of my “sub-subject” code that, instead of echo’ing HTML, echo’ed a JSON of the variables I was interested in with json_encode.

Then the other file used json_decode(`php sub-subject-json.php`);. The backtick operator executes a shell command, in this case, php itself called with the file I want to look at.

So, for example, where previously I might have had

minion.php

<?php
  $name = 'Steve';
  $attack = 3;
  $damage = '1d6+3';
?><!DOCTYPE html>
<html>
<head><title><?php echo $name; ?></title></head>
<body>
  <h1><?php echo $name; ?></h1>
  <p><?php echo formatBonus($attack) . " $damage"; ?>
</body>
</html>

Now I have

minion-core.php

<?php
  $name = 'Steve';
  $attack = 3;
  $damage = '1d6+3';
?>

minion.php

<?php require_once('minion-core.php'); ?><!DOCTYPE html>
<html>
<head><title><?php echo $name; ?></title></head>
<body>
  <h1><?php echo $name; ?></h1>
  <p><?php echo formatBonus($attack) . " $damage"; ?>
</body>
</html>

minion-json.php

<?php
  require_once('minion-core.php');
  header('Content-Type: application/json; charset=utf-8');
  echo json_encode([
    'name' => $name,
    'attack' => $attack,
    'damage' => $damage,
  ]);
?>

And then my main file can include

leader.php

$steve = json_decode(`php minion-json.php`);

This is a nasty, ugly hack. But it does work, and it works without refactoring everything I’ve written.

KRyan
  • 7,308
  • 2
  • 40
  • 68