Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Namespacing with eval() and include() does not work as expected

I am just messing around and I've come across this:


Doesn't work

<?php
namespace first{
    include 'data:text/plain, <?php function a_func(){echo "hi";}';
    a_func();
}
namespace second{
    include 'data:text/plain, <?php function a_func(){echo "bye";}';
    a_func();
}

[29-Apr-2016 14:12:42 America/New_York] PHP Fatal error: Cannot redeclare a_func() (previously declared in data:text/plain, <?php function a_func(){echo "hi";}:1) in data:text/plain, <?php function a_func(){echo "bye";} on line 1

Doesn't work

<?php
namespace first{
    eval('function a_func(){echo "hi";}');
    a_func();
}
namespace second{
    eval('function a_func(){echo "bye";}');
    a_func();
}

[29-Apr-2016 14:19:21 America/New_York] PHP Fatal error: Cannot redeclare a_func() (previously declared in C:\path\test.php(3) : eval()'d code:1) in C:\path\test.php(7) : eval()'d code on line 1

Works

<?php
namespace first{
    function a_func(){echo "hi";}
    a_func();
}
namespace second{
    function a_func(){echo "bye";}
    a_func();
}

Tested in PHP 5.6.20 and 7.0.5


Is this a bug? Feature? Purposefully implemented?


Extra credit: How do I make either the include() or eval() work?

like image 332
MonkeyZeus Avatar asked Apr 29 '16 18:04

MonkeyZeus


1 Answers

include and eval cause the compiler to process their input as if it is coming from a separate file in both cases.

This means that your namespace declarations in the setup code don't transfer to the code coming in from include/eval, and the functions which are defined there are defined in the global namespace. You can verify this easily with

<?php
namespace outer;

eval('function func(){}');
var_dump(function_exists('\outer\func'));    // false
var_dump(function_exists('\func'));          // true

To get the expected behavior you must include the namespace declarations in the code being pulled in:

<?php
namespace first{
    include 'data:text/plain,<?php namespace first; function a_func(){echo "hi";}';
    a_func();
}
namespace second{
    include 'data:text/plain,<?php namespace second; function a_func(){echo "bye";}';
    a_func();
}

and

<?php
namespace first{
    eval('namespace first; function a_func(){echo "hi";}');
    a_func();
}
namespace second{
    eval('namespace second; function a_func(){echo "bye";}');
    a_func();
}
like image 171
Jon Avatar answered Nov 15 '22 00:11

Jon