Search code examples
phpfunctionmethodsrequirekeyword

PHP | What does 'use function function_name;' (where function is a PHP built-in function) do?


I've bumped into some PHP code which uses the use keyword slighty different than what I've seen before. I saw it in the Slim framework source code actually.

use function array_pop;    // --> confusion :/
use function dirname;      // --> confusion :/
use function file_exists;  // --> confusion :/
use function sprintf;      // --> confusion :/
use function is_readable;  // --> confusion :/
use function is_writable;  // --> confusion :/

The source code from is line 24 to 29.

I do know that the keyword use is for including classes

use Psr\Container\ContainerInterface; // --> class
use Psr\Http\Message\ResponseFactoryInterface; // --> class

Or for adding outer scope variables in functions' closure

$array = array('foo', 'bar', 'baz');
$prefix = uniqid();

$array = array_map(function ($elem) use ($prefix) {  // -> here the use keyword is clear
    return $prefix . $elem;
}, $array);

But the use keyword in this case declared on top of the script and in front of functions is really strange, besides they all are built-in function?!.

Question

  • What does use function [built-in-function-name]; do in PHP (PHP "^7.4 || ^8.0")?

Solution

  • Ok is actually pretty easy, the main issue was, that I did not read properly the documentation or I just miss the part, is true though that the use keyword is widely used in PHP, besides with different functionality all together. Either way, thanks for whom helped me figured out in the comment section[ (@riggsfolly, @peterm, @eis, @david) of the question and after good reading and testing I'd decided to post the answer my self.


    Quick Answer

    The use function [some_function] is a namespace which defines / import that function for a particular place, this place being the namespaced section givin possibility to have same named function from different namespace and even modifying the name with alias, both for functions and namespace all together.

    It can be a user defined namespace, or the global namespace

    In this case, calling built-in function this way merely for style / clarity but also may PHP Performance Tip: Use fully-qualified function calls when working with namespaces


    Detailed Answer

    So the usekeyword is scattered with these functionalities:

    • Namespace Import / Include: Modules (as packages), Classes, Traits, Interfaces, functions, constants
    • Use outer scope of variables in closure functions
    • Inject traits in Classes.

    So my question refers to the first point Import / Include (Functions).

    The namespace are somehow more evident when using Classes, as soon as a namespace is declared on the script, that script becomes relative to that namespace and not the global anymore. Hence, if you then call any classes that aren't defined in the very same script without specify the namespace, will result in error, example:

    <?php    
    
        namespace A\B\C;
        class Exception extends \Exception
        {
        }
        
        $a = new Exception('hi'); // $a is an object of class A\B\C\Exception
        $b = new \Exception('hi'); // $b is an object of class Exception
        
        $c = new ArrayObject; // fatal error, class A\B\C\ArrayObject not found
    
    ?>
    

    But even more clear example is this:

    <?php
    namespace A\B\C;
    $b = new Exception('hi'); // Uncaught Error: Class "A\B\C\Exception"
    

    By removing the namespace, it goes back to the global context

    <?php
    $b = new Exception('hi'); // no errors..
    

    However, this is not happening with the const and functions, that's why is little less obvious and will silently fall back to the outer scope if not found.

    For functions and constants, PHP will fall back to global functions or constants if a namespaced function or constant does not exist.

    <?php
    namespace A\B\C;
    
    const E_ERROR = 45;
    function strlen($str)
    {
        return \strlen($str) - 1;
    }
    
    echo E_ERROR, "\n"; // prints "45"
    echo INI_ALL, "\n"; // prints "7" - falls back to global INI_ALL
    
    echo strlen('hi'), "\n"; // prints "1"
    if (is_array('hi')) { // prints "is not array"
        echo "is array\n";
    } else {
        echo "is not array\n";
    }
    ?>
    

    Finally, for some example regarding my question: File functions.php <?php

    namespace MyApp\Package;
    
    //use function var_dump;
    function var_dump($var)
    {
        echo '[', __NAMESPACE__, '] don\'t wnat to do that...<br/>';
    }
    function explode($separator, $some_string)
    {
        echo '[', __NAMESPACE__, '] opps, bomb failed :(...<br/>';
    }
    

    File index.php

    <?php
    
    namespace MyApp;
    require_once 'functions.php';
    
    use MyApp\Package; // Demostrate that we can 'import' the entire package namespace
    use function MyApp\Package\var_dump; // Import the function only
    
    class A
    {
        public static function say() {
            $a = "a";
            $b = "b";
            $data = ['a' => $a, 'b' => $b];
            echo var_dump($data); // --> Calling the namespaced function
        }
        public static function sayReal()
        {
            $a = "a";
            $b = "b";
            $data = ['a' => $a, 'b' => $b];
            echo \var_dump($data); // -> with \ we make the lookup fully-qualified and falls back to global
        }
        public static function explodeBadBomb($bomb="something to explode")
        {
            Package\explode(" ",$bomb); // -> demostrate that we can namespaced in withing blocks and statements
        }
        public static function explodeGooodBomb($bomb="something to explode")
        {
            echo print_r(\explode(" ", $bomb)); // again calling the built-in
        }
    }
    A::say();               // [MyApp\Package] don't wnat to do that...
    A::sayReal();           // array(2) { ["a"]=> string(1) "a" ["b"]=> string(1) "b" }
    A::explodeBadBomb();    // MyApp\Package] opps, bomb failed :(...
    A::explodeGooodBomb();  // Array ( [0] => something [1] => to [2] => explode ) 
    

    Documentation

    More on performance improvement

    Related StackOverflow Questions / Answers