rfc:use_function

PHP RFC: Importing namespaced functions

Introduction

PHP offers the ability to import namespaces and types (classes/interfaces/traits) via the use statement. This capability however does not exist for functions. As a result, working with namespaced functions is rather cumbersome.

A function can only be referenced without fully qualifying it, if the calling code is in the same namespace as the function:

namespace foo\bar {
    function baz() {
        return 'foo.bar.baz';
    }
}
 
namespace foo\bar {
    function qux() {
        return baz();
    }
}
 
namespace {
    var_dump(foo\bar\qux());
}

It is possible to avoid fully qualifying the name by importing the namespace that the function is defined in. But that namespace must still be referenced when calling the function:

namespace foo\bar {
    function baz() {
        return 'foo.bar.baz';
    }
}
 
namespace {
    use foo\bar as b;
    var_dump(b\baz());
}

You cannot import the function directly. PHP does not currently support that.

Proposal

The proposal is to combine existing keywords to a new sequence that allows importing functions into a namespace. This should make namespaced functions less of a pain to use and discourage placing them in the global namespace.

Since functions and classes are in separate namespaces, it is not feasible to use the use keyword for both, as it would likely result in conflicts and overhead.

Instead of introducing a new keyword, it would be possible to combine use and function to a sequence. This new use function combo would work as follows:

namespace foo\bar {
    function baz() {
        return 'foo.bar.baz';
    }
    function qux() {
        return baz();
    }
}
 
namespace {
    use function foo\bar\baz, foo\bar\qux;
    var_dump(baz());
    var_dump(qux());
}

All of this applies not only to functions, but also to namespaced constants. For consistency, a use const sequence should also be introduced, that does the same thing for constants:

namespace foo\bar {
    const baz = 42;
}
 
namespace {
    use const foo\bar\baz;
    var_dump(baz);
}

Just like classes, it should be possible to alias imported functions and constants:

namespace {
    use function foo\bar as foo_bar;
    use const foo\BAZ as FOO_BAZ;
    var_dump(foo_bar());
    var_dump(FOO_BAZ);
}

General questions & answers

Why not just import a namespace?

While it's true that you can import a namespace and alias it to a single character, this is not necessary for classes, so it makes no sense to require it for functions.

There are two specific use cases where importing a function can significantly improve the readability of code.

Tiny libraries

Libraries which are just collections of functions can benefit from this. They can be namespaced under (for example) the author's name, e.g. `igorw\compose()`. This prevents namespace clashes.

The users of that function don't care about who the author is, they just want `compose()`. They don't want to invent a new meaningless alias just to use the function.

Domain specific languages

Functions can be treated as an extension of the language, or to be used to create a custom meta-language. An example of this is building a HTML tree, but this could be anything, really.

A HTML building DSL:

use function html\div, html\p, html\em;
 
$html = div(p('Some', em('Text')));

Avoiding noise and clutter is really important to make this usable and readable.

Global namespace fallback

Currently PHP will search for functions in the local namespace first, then fall back to the global one. For functions imported by a use function statement, there should be no fallback.

namespace foo\bar {
    function strlen($str) {
        return 4;
    }
}
 
namespace {
    use function foo\bar\strlen;
    use function foo\bar\non_existent;
    var_dump(strlen('x'));
    var_dump(non_existent());
}

The call to strlen is no longer ambiguous. non_existent is no longer looked up in the global namespace.

Why is "use function" needed instead of just "use"?

In PHP, functions and classes are stored in separate namespaces. A function `foo\bar` and a class `foo\bar` can co-exist, because it is possible to infer from the context if the symbol is used as a class or a function:

namespace foo {
    function bar() {}
    class bar {}
}
 
namespace {
    foo\bar(); // function call
    new foo\bar(); // class instantiation
    foo\bar::baz(); // static method call on class
}

If use were changed to support functions as well, it would introduce BC breaks.

An example:

namespace {
    function bar() {}
}
 
namespace foo {
    function bar() {}
}
 
namespace {
    use foo\bar;
    bar();
}

The behaviour changed, when use was changed. Depending on your PHP version, a different function will be called.

Function autoloading

Function autoloading is beyond the scope of this RFC.

Backward Incompatible Changes

No BC breaks.

Proposed PHP Version(s)

PHP 5.6.x

SAPIs Impacted

None.

Impact to Existing Extensions

None.

New Constants

None.

php.ini Defaults

None.

Open Issues

None yet.

Patches and Tests

There is a patch against PHP-5.6 (currently master) as a GitHub pull request.

References

Rejected Features

- None.

Vote

The voting period is 15.08.2013 until 29.08.2013.

RFC/use_function
Real name Yes? No?
ab (ab)  
aharvey (aharvey)  
alan_k (alan_k)  
cpriest (cpriest)  
fa (fa)  
gooh (gooh)  
indeyets (indeyets)  
ircmaxell (ircmaxell)  
kalle (kalle)  
laruence (laruence)  
levim (levim)  
lstrojny (lstrojny)  
mfonda (mfonda)  
mike (mike)  
patrickallaert (patrickallaert)  
reeze (reeze)  
salathe (salathe)  
seld (seld)  
stas (stas)  
yohgaki (yohgaki)  
Final result: 16 4
This poll has been closed.

Changelog

  • 2013-08-08 1.1.1 Added example of aliasing
  • 2013-07-23 1.1.0 Added support for constants with `use const`
  • 2013-07-22 1.0.1 FAQ “why 'use function'?”
  • 2013-07-19 1.0.0 First version published for discussion
rfc/use_function.txt · Last modified: 2013/12/06 11:27 by igorw