tags:

views:

1122

answers:

4

If the code is the same, there appears to be a difference between:

include 'external.php';

and

eval('?> . file_get_contents('external.php') . '<?php);

What is the difference? Does anybody know?


I am actually pretty sure there is a difference. I just found out. I have got a large piece of ugly generated php in my database*. By creating my own streamWrapper I am able to include it directly from the database. However, I wanted to see how this compared to eval in terms of performance. So, I wrote a query that gets the php from the database and eval'd it as above. However, while the include works, the eval does not...

+5  A: 

AFAIK you can't take advantage of php accelerators if you use eval().

niteria
I came here because the top line worked for me, while the second did not - this turned out to be a strange caveat where eval needs to end with a semi-colon, even if it's after "<?php"Anyway, that is the reason I put down a simplified version of the problem. In reality, the choice is between: `get $body from db with query, eval($body)` and `include 'db://body'` where the last one has a 400-line class to make it possible to do that.However, since you mentioned php accelerators, do they work when using the strange include I showed you? (that gets the data from the database)
Jasper
AFAIK you have to have a real file on filesystem.
niteria
...and you shouldn't be concerned about it unless you have performance problem.
niteria
That first comment of yours can be explained in two ways. (1) You don't think a php accelerator can help or (2) You don't believe what I am saying about an include from a database. I'll assume you meant the first, as otherwise you are obviously mistaken (I currently have a copy running with that technique, and I could point you to the dark corners of the php manuals that I followed to get there). As such, I guess that makes no difference between the two. I'll probably go for the include as it allows me to use my two ways of saving with just about no differences in code.
Jasper
And the reason I am worried about it is that I am not building a piece of software that is supposed to serve me on one pc ever - instead I am making a piece of software that should be able to run on any pc anyone wants it installed on (much like is the case with forum software), as such an important design decision (how will I implement compiling to the database) early in development is quite essential and performance matters even if there's currently no problem.
Jasper
I meant that AFAIK php accelerators only work with real files on filesystem. Building for php accelerators will most likely complicate your code (you have to check if files are writable etc.) and it is possible it wouldn't make any visible improvement. If they're just template files, my guess is that it won't change anything.
niteria
You're very right, I should not build for php accelerators - I just meant if of the two options I can use one has bad and one has good support for php accelerators, then that is something to weigh in.As currently used, an accelerator would not be able to see much difference between my database-file and a remote file gotten over http. This means that it probably differs per accelerator, as some may have taken account for that as well, while others have not - I say this because I just looked it up and there also are accelerators that cache eval-code (though in a different manner than files)
Jasper
@niteria Just wanted to point out that you say AFAIK too much.
leek
+1  A: 

I found the answer myself. Brace yourself, it's ugly:

include 'external.php';

is not equivalent to

eval('?> . file_get_contents('external.php') . '<?php');

because it is equivalent to:

eval('?> . file_get_contents('external.php') . '<?php;');

Note the semicolon after <?php yuck, it's ugly, but it makes the code work. And as it turns out that in my case, eval was about 10-20% faster...

Jasper
thanks for the semicolon trick, it was driving me nuts!
amartin
isn't eval("?>".file_get_contents('external.php')); the same as include 'external.php'; ??
YuriKolovsky
YuriKolovsky, you are right leaving out the the php-opening tag is an alternative to following it up with a semicolon.
Jasper
+1  A: 

If you are using a webserver on which you have installed an opcode cache, like APC, eval will not be the "best solution" : eval'd code is not store in the opcode cache, if I remember correctly (and another answer said the same thing, btw).

A solution you could use, at least if the code is not often changed, is get a mix of code stored in database and included code :

  • when necessary, fetch the code from DB, and store it in a file on disk
  • include that file
  • as the code is now in a file, on disk, opcode cache will be able to cache it -- which is better for performances
  • and you will not need to make a request to the DB each time you have to execute the code.

I've worked with software that uses this solution (the on-disk file being no more than a cache of the code stored in DB), and I worked not too bad -- way better that doing loads of DB requests of each page, anyway...

Some not so good things, as a consequence :

  • you have to fetch the code from the DB to put it in the file "when necessary"
    • this could mean re-generating the temporary file once every hour, or deleting it when the entry in DB is modified ? Do you have a way to identify when this happens ?
  • you also have to change your code, to use the temporary file, or re-generate it if necessary
    • if you have several places to modifiy, this could mean some work

BTW : would I dare saying something like "eval is evil" ?

Pascal MARTIN
I'm sorry but your suggestion is completely irrelevant. I am writing some software and I made it so that it would only use files. I wanted to provide an alternative by the use of a database for when writing files is not an option, thus I ended up with this.However, we are only talking about one db query and one eval statement. And the speed is not all that bad: 1 : 2 for include from file : include from db, 10 : 8 for include from db : eval from db.Anyway, I do wonder whether a include from db does get cached...Oh, and the reason I came here was that missing semi-colon driving me crazy
Jasper
OK, then ; sorry about that ^^
Pascal MARTIN
A: 

This lets you include a file assuming file wrappers for includes is on in PHP:

function stringToTempFileName($str)
{
    if (version_compare(PHP_VERSION, '5.1.0', '>=') && strlen($str < (1024 * 512))) {
        $file = 'data://text/plain;base64,' . base64_encode($str);
    } else {
        $file = Utils::tempFileName();
        file_put_contents($file, $str);
    }
    return $file;
}

... Then include that 'file.' Yes, this will also disable opcode caches, but it makes this 'eval' the same as an include with respect to behavior.

Jaimie Sirovich
Man, what do you guys around here have with providing related data instead of answering the question? Worse, I have provided the answer to my own question months ago and yet such a message pops up.Let me explain again, I asked what is the difference - and the difference was that the eval option considered your statement unfinished because there was no semicolon.So yes, it is indeed possible to use a temp file or the data wrapper, but that does not have anything to do with my question.
Jasper
Your statement is even more irrelevant. I was simply offering a workaround re: the slight differences in behavior between eval() and include() language constructs.Your (ungrateful) complaint only indicates that you fail to perceive the fact that this is a community where others can benefit from thoughtful comments left by a well-meaning programmer who does perceive the same. You're not the only programmer in this world.fail();
Jaimie Sirovich
I'd say I have more experience on this site than you do. Nevertheless, when asking "how do you do A?" an answer "this is how you can do B, which is what you were probably using A for" is pretty useless if part of the question was that I was NOT trying to do B.
Jasper
Also, my question was "What are the differences?" The only difference I know of has been found and solves. Now you come with a way that solves all the differences. If you were to explain _which_ differences you were fixing this way, your answer would have some relevance.
Jasper