2

When we include files in PHP, they are somehow cached. So, if one contains a class definition, when we try to include it twice, we will get an error saying "Can not redeclare class".

But is it possible to get include file code invoked with a scope set to current function, let's say?

E.g. if we have two files:

moo.php:

<?php
class Moo
{
  function __construct()
  {
    echo "hello, world!" . PHP_EOL;
  }
}
?>

main.php:

<?php
function foo()
{
  include("moo.php");
  new Moo();
}

foo();

new Moo(); // <-- here should be an error saying "could not find class Moo"

include("moo.php");

new Moo(); // <-- and here should not
?>

As far as i've tried, not eval(file_get_contents("moo.php"));, nor namespaces either gave no expected effect with a least of code...

Problematic
  • 17,567
  • 10
  • 73
  • 85
shybovycha
  • 11,556
  • 6
  • 52
  • 82

4 Answers4

1

Use require_once() and include_once(). They'll make PHP remember what files were included, and NOT include them again elsewhere in the code. After the first include/require, subsequent ones on the same file will essentially become a null-op.

Marc B
  • 356,200
  • 43
  • 426
  • 500
  • no, i need to leave the possibility to instantiate class further in the code (if the proper file is included only). – shybovycha Aug 26 '11 at 18:11
  • You can do `$var = new Class();` as many times you want, you know. – Marc B Aug 26 '11 at 18:37
  • as i said, __if proper file is included ONLY__ – shybovycha Aug 26 '11 at 18:55
  • Yes, and you can do `include_once('myclass.php')` as many times as you want, because after the FIRST time, PHP will no longer actually include the file. So everywhere you want to use your moo class, do an include_once and problem solved. – Marc B Aug 26 '11 at 18:57
  • it's just like C++: you can instantiate class only if you know its definition. surem you should use namespaces then, but in this case, seems that i need some kind of 'namespace for a few lines'... but that code will be run within the loop so it is not a good idea to use namespaces... – shybovycha Aug 26 '11 at 18:59
  • If you don't know which file a class is defined in, how do you expect PHP to be able to figure out for you? It'd be ludicrously inefficient to have to scan all .php files to find a class you're trying to load. Given you say you want to prevent further instantiation, then use a Singleton object. But you'd still need to do the include_once to get it loaded wherever it may be called on. – Marc B Aug 26 '11 at 19:01
  • let me explain you the details: let us have three files - Core.php (with class Core which code __SHOULD NOT BE CHANGED__), Moo.php (with class Moo, which should replace Core class for the `main()` function call) and index.php (with `main()` function call and some routines after that). We should include Core.php everywhere while Moo.php should be included for a `main()` call, replace Core's functionality for that scope and then become inavaliable. To make that replacement work again, we should include `Moo.php` again even within index.php. – shybovycha Aug 26 '11 at 19:10
  • You can't "replace" functionality like that: http://stackoverflow.com/questions/137006/php-redefine-class-methods-or-class – Marc B Aug 26 '11 at 19:11
0

Namespaces should fix this prob -> http://php.net/manual/en/language.namespaces.php

pmilb
  • 1
  • oops, just saw your last line under your code :) you sure you're using namespaces correctly? – pmilb Aug 26 '11 at 17:12
  • yeah, i need to include that file within one function, create a class (described in included file) instance and prevent further instantianting without including that file. – shybovycha Aug 26 '11 at 18:10
0

You should try implementing autoload for your classes. It will help prevent things like this.

afuzzyllama
  • 6,538
  • 5
  • 47
  • 64
-2

Seems that monkey patching did the trick:

<?php
$code = <<<EOS
namespace monkeypatch;

\$s = "moofoo";

echo "This should six, but is it?: " . strlen(\$s) . PHP_EOL;
echo "Whoa! And now it is six, right?: " . \strlen(\$s) . PHP_EOL;

function strlen(\$x) 
{
    return -3.14;
}
EOS;

eval($code);

echo "While out of namespaces it is still six...: " . strlen("moofoo") . PHP_EOL;

Lots of thanks to Marc B. for the hint!

Community
  • 1
  • 1
shybovycha
  • 11,556
  • 6
  • 52
  • 82
  • I have no idea what you are actually trying to achieve, and using an `eval()` any manner is just bad practice. As for ['monkey patching'](http://www.codinghorror.com/blog/2008/07/monkeypatching-for-humans.html)... – afuzzyllama Aug 26 '11 at 19:48
  • @afuzzyllama, do you get a better idea on how to use some file code within one code block without making it avaliable to other code parts? – shybovycha Aug 27 '11 at 19:15
  • are you trying to override a php core function or add your own function? – afuzzyllama Aug 27 '11 at 19:20
  • @afuzzyllama i have my "core" code which i should override (for a one code block - in others that overrides should be cancelled) without changing it. One more problem is that overriding code could be class or just a php code either. – shybovycha Aug 28 '11 at 06:37