Hello, Internals!

I've implemented an alpha implementation of the Extension Functions in PHP.
Basically, it's a syntax sugar of the imperative call of the function with
the passing the object as a first argument, but anyway.

Here is how it looks like in Kotlin:
https://kotlinlang.org/docs/extensions.html

In PHP it might looks like so:

function stdClass.getName() {
    return $this->name;
}

$obj = new stdClass;
$obj->name = 'Dmitrii';
echo $obj->getName(); // prints Dmitrii

so desugared version is:

function getName(stdClass $obj) {
    return $obj->name;
}

$obj = new stdClass;
$obj->name = 'Dmitrii';
echo getName($obj); // prints Dmitrii

Quite simple improvement, but a really convenient way to "attach" behaviour
and extend vendor code to make it more readable.

Functions register as usual, using `use` keyword. So there are no
surprises when you call a function which does not exist, only an implicit
way to specify the function.

"Attaching" the function with the name of an existing member
function raises an exception.
But you may juggle different functions from different namespaces:

namespace A;

use function aa; // from global namespace
OR
use function B\aa; // from B namespace
OR
use function B\aa as Baa; // from B namespace with alias

`use function` construction may be enlarged with the "extension" keyword:
use function getTime; // regular function
use extension function getTime; // extension function, unable to call
without correct receiver

As in Kotlin, it should access only public members.

class A { private $name; }

function A.getName() {
    return $this->name; // raises an exception because private and
protected members aren't available
}

Supporting types DNF is under question, but I'd leave them as future scope.

function ((A&B)|null).smth() { ... }
but it could be resolved to
function smth((A&B)|null $obj) { ... }

The dot as a delimiter is also under the question, here are a few options:

function stdClass::getName();
function stdClass->getName();
function stdClass.getName();
function ::stdClass getName();
function stdClass<-getName();
function getName of stdClass();

etc.

I've tried to implement the feature through attaching a function to the
class functions scope, which is wrong and does not follow the requirements.
It has memory leaks.
https://github.com/php/php-src/compare/master...xepozz:php-src:extension-functions?expand=1#diff-1dd36b02e5025ec3a5a546f8e41374ee4fc18c411bce447dd1dc2952329ccbe6R25

I also thought about adding this feature as a custom attribute behaviour,
but it's a way difficult:

#[Extension("stdClass")]
function hasName(): bool {
    return $this->name;
}

I can try to implement the de-sugared version to make it work correctly.

---

WDYT guys?

-- 
Best regards,
Dmitrii Derepko.
@xepozz

Reply via email to