Welcome! Log In Create A New Profile

Advanced

[PHP-DEV] New Feature: Fully qualified class name resolution as scalar with class keyword

Posted by Ralph Schindler 
Hi all,

There are many different use cases were in code we expect classes names
as arguments to functions as fully qualified names. We do this in ZF a
lot with our Service Location and DI components, but also with our code
reflection API, etc. A more interesting use case I would like to call
out is with PHPUnit, for example in a test, you might find this:

$mock = $this->getMock('A\Namespaced\ClassName');

This becomes cumbersome when you are dealing with lots of strings about
lots of class names. This is also an area where, currently, namespace
declaration and use statements offer no real support.

The patch located here:

https://github.com/ralphschindler/php-src/commit/02210d51851a96d723fbedcfc64cde9f9ae2b22a

.... implements the ability for a developer to leverage the file's
namespace declaration and use statements to be able to produce a scalar
(string) of the class name that can be then used, for example, as an
argument to a function elsewhere.

This overloads the "class" keyword, and by virtue of the existing usage
of "class" this feature is completely backwards compatible. All
existing tests pass. For example, the above PHPUnit snipped would become:

use A\Namespaced\ClassName;
$mock = $this->getMock(ClassName::class);

Another example with reflection:

use SomeOther\FullyNamespaced\ClassElsewhere as CE;
$r = new ReflectionClass(CE::class);

More examples from the test file:

namespace Foo\Bar {
class Baz {}
var_dump(Moo::CLASS); // "Foo\Bar\Moo"
}

namespace {
use Bee\Bop as Moo,
Foo\Bar\Baz;

var_dump(Baz::class); // "Foo\Bar\Baz"
var_dump(Boo::class); // "Boo"
var_dump(Moo::CLASS); // "Bee\Bop"
var_dump(\Moo::Class); // "Moo"

$class = Baz::class; // assign class as scalar to var
$x = new $class;
var_dump($x); object(Foo\Bar\Baz)#1 (0) {}
}


What do you guys think?

-ralph

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
I used to implement `public static function getClass() { return
get_called_class(); }`, so I really like this one, makes it also easier for
IDEs when refactoring code :)

I was wondering about `class A { const CLASS = 'hello'; }` but that would
cause an unexpected `T_CLASS`, so I guess there's no conflicts...


Marco Pivetta

http://twitter.com/Ocramius

http://marco-pivetta.com



On 14 April 2012 21:50, Ralph Schindler <[email protected]> wrote:

> Hi all,
>
> There are many different use cases were in code we expect classes names as
> arguments to functions as fully qualified names. We do this in ZF a lot
> with our Service Location and DI components, but also with our code
> reflection API, etc. A more interesting use case I would like to call out
> is with PHPUnit, for example in a test, you might find this:
>
> $mock = $this->getMock('A\Namespaced\**ClassName');
>
> This becomes cumbersome when you are dealing with lots of strings about
> lots of class names. This is also an area where, currently, namespace
> declaration and use statements offer no real support.
>
> The patch located here:
>
> https://github.com/**ralphschindler/php-src/commit/**
> 02210d51851a96d723fbedcfc64cde**9f9ae2b22ahttps://github.com/ralphschindler/php-src/commit/02210d51851a96d723fbedcfc64cde9f9ae2b22a
>
> ... implements the ability for a developer to leverage the file's
> namespace declaration and use statements to be able to produce a scalar
> (string) of the class name that can be then used, for example, as an
> argument to a function elsewhere.
>
> This overloads the "class" keyword, and by virtue of the existing usage of
> "class" this feature is completely backwards compatible. All existing
> tests pass. For example, the above PHPUnit snipped would become:
>
> use A\Namespaced\ClassName;
> $mock = $this->getMock(ClassName::**class);
>
> Another example with reflection:
>
> use SomeOther\FullyNamespaced\**ClassElsewhere as CE;
> $r = new ReflectionClass(CE::class);
>
> More examples from the test file:
>
> namespace Foo\Bar {
> class Baz {}
> var_dump(Moo::CLASS); // "Foo\Bar\Moo"
> }
>
> namespace {
> use Bee\Bop as Moo,
> Foo\Bar\Baz;
>
> var_dump(Baz::class); // "Foo\Bar\Baz"
> var_dump(Boo::class); // "Boo"
> var_dump(Moo::CLASS); // "Bee\Bop"
> var_dump(\Moo::Class); // "Moo"
>
> $class = Baz::class; // assign class as scalar to var
> $x = new $class;
> var_dump($x); object(Foo\Bar\Baz)#1 (0) {}
> }
>
>
> What do you guys think?
>
> -ralph
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>
Am 14.04.2012 23:14, schrieb Marco Pivetta:
> I used to implement `public static function getClass() { return
> get_called_class(); }`, so I really like this one, makes it also easier for
> IDEs when refactoring code :)
>
> I was wondering about `class A { const CLASS = 'hello'; }` but that would
> cause an unexpected `T_CLASS`, so I guess there's no conflicts...

I have

class A { const _CLASS = __CLASS__; }

in many classes. This feature would help a lot.


>
>
> Marco Pivetta
>
> http://twitter.com/Ocramius
>
> http://marco-pivetta.com
>>
>> --
>> PHP Internals - PHP Runtime Development Mailing List
>> To unsubscribe, visit: http://www.php.net/unsub.php
>>
>>
>


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
> I used to implement `public static function getClass() { return
> get_called_class(); }`, so I really like this one, makes it also easier
> for IDEs when refactoring code :)

Oh completely, that is one of the major benefits. My current workflow
for refactoring is to refactor with the built-in support, but then also
having to go find/replace on the full class name, just in case.

-ralph

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Hi Ralph, hi everybody,

given the clear use case and the simplicity of the patch, a very good idea.

With regards,
Lars

Am 15.04.2012 um 16:13 schrieb Ralph Schindler:

>
>> I used to implement `public static function getClass() { return
>> get_called_class(); }`, so I really like this one, makes it also easier
>> for IDEs when refactoring code :)
>
> Oh completely, that is one of the major benefits. My current workflow for refactoring is to refactor with the built-in support, but then also having to go find/replace on the full class name, just in case.
>
> -ralph
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
2012/4/14 Ralph Schindler <[email protected]>:
> Hi all,
>
> There are many different use cases were in code we expect classes names as
> arguments to functions as fully qualified names.  We do this in ZF a lot
> with our Service Location and DI components, but also with our code
> reflection API, etc.  A more interesting use case I would like to call out
> is with PHPUnit, for example in a test, you might find this:
>
>  $mock = $this->getMock('A\Namespaced\ClassName');
>
> This becomes cumbersome when you are dealing with lots of strings about lots
> of class names.  This is also an area where, currently, namespace
> declaration and use statements offer no real support.
>
> The patch located here:
>
> https://github.com/ralphschindler/php-src/commit/02210d51851a96d723fbedcfc64cde9f9ae2b22a
>
> ... implements the ability for a developer to leverage the file's namespace
> declaration and use statements to be able to produce a scalar (string) of
> the class name that can be then used, for example, as an argument to a
> function elsewhere.
>
> This overloads the "class" keyword, and by virtue of the existing usage of
> "class" this feature is completely backwards compatible.  All existing tests
> pass.  For example, the above PHPUnit snipped would become:
>
>  use A\Namespaced\ClassName;
>  $mock = $this->getMock(ClassName::class);
>
> Another example with reflection:
>
>  use SomeOther\FullyNamespaced\ClassElsewhere as CE;
>  $r = new ReflectionClass(CE::class);
>
> More examples from the test file:
>
>  namespace Foo\Bar {
>    class Baz {}
>    var_dump(Moo::CLASS); // "Foo\Bar\Moo"
>  }
>
>  namespace {
>    use Bee\Bop as Moo,
>        Foo\Bar\Baz;
>
>    var_dump(Baz::class); // "Foo\Bar\Baz"
>    var_dump(Boo::class); // "Boo"
>    var_dump(Moo::CLASS); // "Bee\Bop"
>    var_dump(\Moo::Class); // "Moo"
>
>    $class = Baz::class; // assign class as scalar to var
>    $x = new $class;
>    var_dump($x);  object(Foo\Bar\Baz)#1 (0) {}
>  }
>
>
> What do you guys think?
>
> -ralph
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>

Hi, Ralph

I really like this feature in general.

One thing I personally dislike in this implementation is the
difference between CLASS and class ... One with and one without
namespaces ...
If we can unify that, this would be a great help in understanding that
feature in future and getting the difference while reading code.
And please don't forget: Code will be written once, maybe rewritten
some times, but it will be read way more times!

Bye
Simon

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
> One thing I personally dislike in this implementation is the
> difference between CLASS and class ... One with and one without
> namespaces ...

I am not quite following. There is no functional difference between
"class", "CLASS", or "Class". The parser is case insensitive with
regards to keywords, which "class" or T_CLASS is on of. The code
snipped I showed there was from the .phpt test that I had included in
the Zend/test code base to ensure it worked and did not break existing
tests.

As per the namespaced and non-namespaced blocks, I was demonstrating how
::class would resolve names regardless of if it were a FQCN or a short
class name. Effectively, you can put ::class behind any "type" name and
it should work as demonstrated.

-ralph


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
2012/4/16 Ralph Schindler <[email protected]>
>
> I am not quite following.  There is no functional difference between
> "class", "CLASS", or "Class".  The parser is case insensitive with regards
> to keywords, which "class" or T_CLASS is on of.  The code snipped I showed
> there was from the .phpt test that I had included in the Zend/test code base
> to ensure it worked and did not break existing tests.
>
> As per the namespaced and non-namespaced blocks, I was demonstrating how
> ::class would resolve names regardless of if it were a FQCN or a short class
> name.  Effectively, you can put ::class behind any "type" name and it should
> work as demonstrated.
>
> -ralph
>

Hi, Ralph

Thanks for clarification.
I was missing the backslash before Moo::Class which lead to that thought.

As the class-definition for Moo is missing, I think it's an empty
class (like Baz) on the root-level defined somewhere else, right?
Otherwise this should do something else than guessing the class-name.

Bye
Simon

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Hey Simon,

> As the class-definition for Moo is missing, I think it's an empty
> class (like Baz) on the root-level defined somewhere else, right?
> Otherwise this should do something else than guessing the class-name.

If you look at the patch, this feature is not doing anything PHP doesn't
already do in other circumstances - demonstrated by the fact that its
only about 4 lines of code ;)

In PHP, in situations like (instanceof):

if ($foo instanceof Bar)

or (catch)

} catch (SomeException $e) {

or (method signature)

public function setFoo(FooInterface $foo)

.... PHP does not invoke the autoloader to determine if the class name
actually exists as a declaration somewhere, it simply resolves it
according to some very specific rules (in the case of this patch,
carried out by zend_resolve_class_name()).

If I am within a namespace and am using a short name without a preceding
"\", it means the class I am referencing exists in the current
namespace. Whether or not that class exists is irrelevant as my short
name can only mean "a class by this name in the current namespace". In
this code:

namespace Foo\Bar {
global $foo;
if ($foo && $foo instance Bar) {
// ...
}
}

.... that you, the developer, intend that your reference to Baz actually
means "Foo\Bar\Baz", it can never mean anything else.

So, in a nutshell, there is no guessing going on ;)
-ralph

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
2012/4/16 Ralph Schindler <[email protected]>
>
> ... PHP does not invoke the autoloader to determine if the class name
> actually exists as a declaration somewhere, it simply resolves it according
> to some very specific rules (in the case of this patch, carried out by
> zend_resolve_class_name()).
>
> If I am within a namespace and am using a short name without a preceding
> "\", it means the class I am referencing exists in the current namespace.
>  Whether or not that class exists is irrelevant as my short name can only
> mean "a class by this name in the current namespace".  In this code:
>
>  namespace Foo\Bar {
>    global $foo;
>    if ($foo && $foo instance Bar) {
>        // ...
>    }
>  }
>
> ... that you, the developer, intend that your reference to Baz actually
> means "Foo\Bar\Baz", it can never mean anything else.
>
> So, in a nutshell, there is no guessing going on ;)
> -ralph

Hi, Ralph

Agree on that. I'd like to have a comment in the test, specially for
this line where you're checking for non-existing classes. It does not
seem to be obvious what should be tested here (at least it was not
obvious for me). This may make it easier to fix stuff if this test
should fail in future.
I don't know if this here is the right test to put the comment in, but
it's at least relying on something global that may change.

Thanks for giving me a deeper knowledge here :)

Bye
Simon

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
So, at current, is this small enough for just a pull request, or does
this deserve its own RFC?

-ralph

On 4/14/12 2:50 PM, Ralph Schindler wrote:
> Hi all,
>
> There are many different use cases were in code we expect classes names
> as arguments to functions as fully qualified names. We do this in ZF a
> lot with our Service Location and DI components, but also with our code
> reflection API, etc. A more interesting use case I would like to call
> out is with PHPUnit, for example in a test, you might find this:
>
> $mock = $this->getMock('A\Namespaced\ClassName');
>
> This becomes cumbersome when you are dealing with lots of strings about
> lots of class names. This is also an area where, currently, namespace
> declaration and use statements offer no real support.
>
> The patch located here:
>
> https://github.com/ralphschindler/php-src/commit/02210d51851a96d723fbedcfc64cde9f9ae2b22a
>
>
> ... implements the ability for a developer to leverage the file's
> namespace declaration and use statements to be able to produce a scalar
> (string) of the class name that can be then used, for example, as an
> argument to a function elsewhere.
>
> This overloads the "class" keyword, and by virtue of the existing usage
> of "class" this feature is completely backwards compatible. All existing
> tests pass. For example, the above PHPUnit snipped would become:
>
> use A\Namespaced\ClassName;
> $mock = $this->getMock(ClassName::class);
>
> Another example with reflection:
>
> use SomeOther\FullyNamespaced\ClassElsewhere as CE;
> $r = new ReflectionClass(CE::class);
>
> More examples from the test file:
>
> namespace Foo\Bar {
> class Baz {}
> var_dump(Moo::CLASS); // "Foo\Bar\Moo"
> }
>
> namespace {
> use Bee\Bop as Moo,
> Foo\Bar\Baz;
>
> var_dump(Baz::class); // "Foo\Bar\Baz"
> var_dump(Boo::class); // "Boo"
> var_dump(Moo::CLASS); // "Bee\Bop"
> var_dump(\Moo::Class); // "Moo"
>
> $class = Baz::class; // assign class as scalar to var
> $x = new $class;
> var_dump($x); object(Foo\Bar\Baz)#1 (0) {}
> }
>
>
> What do you guys think?
>
> -ralph


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
May I suggest using foo::__CLASS__ instead of foo::class ? It's longer, but
closer to what already exists for this semantic (class name as string),
don't you think ?


So, at current, is this small enough for just a pull request, or does this
> deserve its own RFC?
>

Personnaly, I would say that an RFC would be good for historical reference
and documentation.

Nicolas
On Sat, Apr 14, 2012 at 9:50 PM, Ralph Schindler
<[email protected]> wrote:
> Hi all,
>
> There are many different use cases were in code we expect classes names as
> arguments to functions as fully qualified names.  We do this in ZF a lot
> with our Service Location and DI components, but also with our code
> reflection API, etc.  A more interesting use case I would like to call out
> is with PHPUnit, for example in a test, you might find this:
>
>  $mock = $this->getMock('A\Namespaced\ClassName');
>
> This becomes cumbersome when you are dealing with lots of strings about lots
> of class names.  This is also an area where, currently, namespace
> declaration and use statements offer no real support.
>
> The patch located here:
>
> https://github.com/ralphschindler/php-src/commit/02210d51851a96d723fbedcfc64cde9f9ae2b22a
>
> ... implements the ability for a developer to leverage the file's namespace
> declaration and use statements to be able to produce a scalar (string) of
> the class name that can be then used, for example, as an argument to a
> function elsewhere.
>
> This overloads the "class" keyword, and by virtue of the existing usage of
> "class" this feature is completely backwards compatible.  All existing tests
> pass.  For example, the above PHPUnit snipped would become:
>
>  use A\Namespaced\ClassName;
>  $mock = $this->getMock(ClassName::class);
>
> Another example with reflection:
>
>  use SomeOther\FullyNamespaced\ClassElsewhere as CE;
>  $r = new ReflectionClass(CE::class);
>
> More examples from the test file:
>
>  namespace Foo\Bar {
>    class Baz {}
>    var_dump(Moo::CLASS); // "Foo\Bar\Moo"
>  }
>
>  namespace {
>    use Bee\Bop as Moo,
>        Foo\Bar\Baz;
>
>    var_dump(Baz::class); // "Foo\Bar\Baz"
>    var_dump(Boo::class); // "Boo"
>    var_dump(Moo::CLASS); // "Bee\Bop"
>    var_dump(\Moo::Class); // "Moo"
>
>    $class = Baz::class; // assign class as scalar to var
>    $x = new $class;
>    var_dump($x);  object(Foo\Bar\Baz)#1 (0) {}
>  }
>
>
> What do you guys think?
Hey Ralph!

I like the proposal :)

A quick note on the patch: As the class name is compile-time
resolvable it should in my eyes also be available as a
`static_scalar`, so that it can be used in initialization lists:

public function doFoo($withClass = ABC::class) {
new $withClass; // or whatever
}

To be available as both a `static_scalar` and a general `scalar` one
should put the rule in the `common_scalar` section.

What do you think?

Nikita

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
@Nicolas: wouldn't __CLASS__ introduce a bit of confusion with the existing
constant?

Marco Pivetta

http://twitter.com/Ocramius

http://marco-pivetta.com



On 17 April 2012 11:17, Nikita Popov <[email protected]> wrote:

> On Sat, Apr 14, 2012 at 9:50 PM, Ralph Schindler
> <[email protected]> wrote:
> > Hi all,
> >
> > There are many different use cases were in code we expect classes names
> as
> > arguments to functions as fully qualified names. We do this in ZF a lot
> > with our Service Location and DI components, but also with our code
> > reflection API, etc. A more interesting use case I would like to call
> out
> > is with PHPUnit, for example in a test, you might find this:
> >
> > $mock = $this->getMock('A\Namespaced\ClassName');
> >
> > This becomes cumbersome when you are dealing with lots of strings about
> lots
> > of class names. This is also an area where, currently, namespace
> > declaration and use statements offer no real support.
> >
> > The patch located here:
> >
> >
> https://github.com/ralphschindler/php-src/commit/02210d51851a96d723fbedcfc64cde9f9ae2b22a
> >
> > ... implements the ability for a developer to leverage the file's
> namespace
> > declaration and use statements to be able to produce a scalar (string) of
> > the class name that can be then used, for example, as an argument to a
> > function elsewhere.
> >
> > This overloads the "class" keyword, and by virtue of the existing usage
> of
> > "class" this feature is completely backwards compatible. All existing
> tests
> > pass. For example, the above PHPUnit snipped would become:
> >
> > use A\Namespaced\ClassName;
> > $mock = $this->getMock(ClassName::class);
> >
> > Another example with reflection:
> >
> > use SomeOther\FullyNamespaced\ClassElsewhere as CE;
> > $r = new ReflectionClass(CE::class);
> >
> > More examples from the test file:
> >
> > namespace Foo\Bar {
> > class Baz {}
> > var_dump(Moo::CLASS); // "Foo\Bar\Moo"
> > }
> >
> > namespace {
> > use Bee\Bop as Moo,
> > Foo\Bar\Baz;
> >
> > var_dump(Baz::class); // "Foo\Bar\Baz"
> > var_dump(Boo::class); // "Boo"
> > var_dump(Moo::CLASS); // "Bee\Bop"
> > var_dump(\Moo::Class); // "Moo"
> >
> > $class = Baz::class; // assign class as scalar to var
> > $x = new $class;
> > var_dump($x); object(Foo\Bar\Baz)#1 (0) {}
> > }
> >
> >
> > What do you guys think?
> Hey Ralph!
>
> I like the proposal :)
>
> A quick note on the patch: As the class name is compile-time
> resolvable it should in my eyes also be available as a
> `static_scalar`, so that it can be used in initialization lists:
>
> public function doFoo($withClass = ABC::class) {
> new $withClass; // or whatever
> }
>
> To be available as both a `static_scalar` and a general `scalar` one
> should put the rule in the `common_scalar` section.
>
> What do you think?
>
> Nikita
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>
> May I suggest using foo::__CLASS__ instead of foo::class ? It's longer,
> but closer to what already exists for this semantic (class name as
> string), don't you think ?
>

As Marco suggested, I think using __CLASS__ would be confusing to some.
__CLASS__ generally means, "where you see this, replace it with the
class you are in right now".

I generally don't like to draw comparisons too closely to Java and .NET,
but Java has this, they call it a "class literal", which works the same
way as described in my new feature:


http://stackoverflow.com/questions/2160788/what-is-a-class-literal-in-java

In .net, if a type is a SystemType.Type object (which I think are all
types), you can simply call a function on it to get the name:

http://msdn.microsoft.com/en-us/library/9f49ew66.aspx

In addition, I am unsure if there would be any BC issues with your
proposed syntax. I do know with mine (::class) does not pose any BC
issues since the class keyword was limited to declaring a class only.
At least, the tests prove this, and I can't find any other usages of
T_CLASS in the parser.

> Personnaly, I would say that an RFC would be good for historical
> reference and documentation.

I think you're right, I'll do this today.

-ralph

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Hi Nikita,

> A quick note on the patch: As the class name is compile-time
> resolvable it should in my eyes also be available as a
> `static_scalar`, so that it can be used in initialization lists:
>
> public function doFoo($withClass = ABC::class) {
> new $withClass; // or whatever
> }
>
> To be available as both a `static_scalar` and a general `scalar` one
> should put the rule in the `common_scalar` section.
>
> What do you think?

I've added this to the patch and Zend/tests:

*
https://github.com/ralphschindler/php-src/compare/master...feature/class-name-scalar

I've also added an RFC page, any thoughts on improving the RFC?

* https://wiki.php.net/rfc/class_name_scalars

-ralph

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
On 2012-04-17, Ralph Schindler <[email protected]> wrote:
> Hi Nikita,
>
> > A quick note on the patch: As the class name is compile-time
> > resolvable it should in my eyes also be available as a
> > `static_scalar`, so that it can be used in initialization lists:
> >
> > public function doFoo($withClass = ABC::class) {
> > new $withClass; // or whatever
> > }
> >
> > To be available as both a `static_scalar` and a general `scalar` one
> > should put the rule in the `common_scalar` section.
> >
> > What do you think?
>
> I've added this to the patch and Zend/tests:
>
> *
> https://github.com/ralphschindler/php-src/compare/master...feature/class-name-scalar
>
> I've also added an RFC page, any thoughts on improving the RFC?
>
> * https://wiki.php.net/rfc/class_name_scalars

In the examples, you mix case:

Boo::class
Moo::Class
\Moo::CLASS

Make sure you note that this is intentional, and that the keyword is
case insensitive -- i.e., changing the case does not alter the use cases
presented.

Also, I'd note why you're selecting "class" as the keyword (basically,
because it _is_ a keyword, and thus will never conflict with any class
constants or method names).

Otherwise, very straight-forward.

--
Matthew Weier O'Phinney
Project Lead | matthew@zend.com
Zend Framework | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Hi!

> May I suggest using foo::__CLASS__ instead of foo::class ? It's longer, but
> closer to what already exists for this semantic (class name as string),
> don't you think ?

I like this. __CLASS__ is already being used as class name, and little
chance of colliding with some code since you're not supposed to be using
__ prefix in your names.

--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
On Tue, Apr 17, 2012 at 6:58 PM, Stas Malyshev <[email protected]> wrote:
> Hi!
>
>> May I suggest using foo::__CLASS__ instead of foo::class ? It's longer, but
>> closer to what already exists for this semantic (class name as string),
>> don't you think ?
>
> I like this. __CLASS__ is already being used as class name, and little
> chance of colliding with some code since you're not supposed to be using
> __ prefix in your names.
From the collisions point of view `class` and `__CLASS__` are equally
safe. They both are lexer keywords, so it's not possible to declare
constants with them as name.

Imho ClassName::class reads nicer and also looks similar to the
similar ClassName.class syntax in Java.

Nikita

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
On 2012-04-17, Stas Malyshev <[email protected]> wrote:
> > May I suggest using foo::__CLASS__ instead of foo::class ? It's longer, but
> > closer to what already exists for this semantic (class name as string),
> > don't you think ?
>
> I like this. __CLASS__ is already being used as class name, and little
> chance of colliding with some code since you're not supposed to be using
> __ prefix in your names.

"class" won't collide anyways, as it's already a keyword, and you can't use it
in your constant or function names. __CLASS__ has bad connotations for me, as it
resolves to the declaring class normally, not the class invoked.

--
Matthew Weier O'Phinney
Project Lead | matthew@zend.com
Zend Framework | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Hi Ralph,

On 17/04/12 10:54, Ralph Schindler wrote:
> I've also added an RFC page, any thoughts on improving the RFC?
>
> * https://wiki.php.net/rfc/class_name_scalars
Are you sure that the example section is correct? Because your first
var_dump is Moo::CLASS but the symbol Moo does not exist yet, only the
class Foo\Bar\Baz was declared at this point.

Btw, interesting patch and nice implementation. I approved.

Best regards.

--
Ivan Enderlin
Developer of Hoa
http://hoa.42/ or http://hoa-project.net/

PhD. student at DISC/Femto-ST (Vesontio) and INRIA (Cassis)
http://lifc.univ-fcomte.fr/ and http://www.inria.fr/

Member of HTML and WebApps Working Group of W3C
http://w3.org/




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
> From the collisions point of view `class` and `__CLASS__` are equally
> safe.

> Imho ClassName::class reads nicer and also looks similar to the
> similar ClassName.class syntax in Java.

The current __CLASS__ could then be written self::class. Looks more
"namespace/object oriented", where __CLASS__ feels procedural?

How would static::class behave ? is it handled by the current patch?
Maybe the test case could be extended to reflect this, and also for
self::class?

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
> var_dump is Moo::CLASS but the symbol Moo does not exist yet, only the
> class Foo\Bar\Baz was declared at this point.

It could exist. It could be a class name handled by an autoloader
somewhere else.

This method of class name resolving operates in the spirit of how our
namespace implementation works. Namespaces don't actually "import"
things into the files symbol table, it makes aliases for them, as such
the namespace implementation alone never triggers an autoload simply b/c
you were talking about a class somewhere.

The ::class resolver essentially does the same thing, for any given name
you are talking about, it will resolve that name against the current
namespace resolution rules.

>
> Btw, interesting patch and nice implementation. I approved.
>
> Best regards.
>

Thanks!
-ralph

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
> How would static::class behave ? is it handled by the current patch?
> Maybe the test case could be extended to reflect this, and also for
> self::class?

Fantastic question. I am unsure how to handle this. Currently, it will
simply resolve those names against the rules (I am sure this is the
wrong behavior.) So,

namespace Foo\Bar { var_dump(self::class); }

Would now produce:

string(12) "Foo\Bar\self"

This is the same with 'self', 'static', and 'parent'. I guess the
question is, should that produce a compile error, or conditionally work
depending on if you are inside of a class declaration or not?

I will add this consideration to the RFC.

-ralph



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
On Sat, Apr 14, 2012 at 12:50 PM, Ralph Schindler
<[email protected]>wrote:

> Hi all,
>
> There are many different use cases were in code we expect classes names as
> arguments to functions as fully qualified names. We do this in ZF a lot
> with our Service Location and DI components, but also with our code
> reflection API, etc. A more interesting use case I would like to call out
> is with PHPUnit, for example in a test, you might find this:
>
> $mock = $this->getMock('A\Namespaced\**ClassName');
>
> [...]
>
>
> This overloads the "class" keyword, and by virtue of the existing usage of
> "class" this feature is completely backwards compatible. All existing
> tests pass. For example, the above PHPUnit snipped would become:
>
> Would it be easy to have a patch that simply allows use of the class name,
or is the "::class" suffix necessary to resolve some ambiguity? Example
usage:

$mock = $this->getMock(A\Namespaced\**ClassName);
# or
use A\Namespaced\ClassName;
$mock = $this->getMock(ClassName);

Would changing the definition for class_name_scalar be sufficient?

class_name_scalar:
class_name { zend_resolve_class_name(&$1, ZEND_FETCH_CLASS_GLOBAL,
1 TSRMLS_CC); $$ = $1; }
;

To my eye, this is the least surprising syntax.
On Tue, Apr 17, 2012 at 9:36 PM, Galen Wright-Watson <[email protected]> wrote:
>Would it be easy to have a patch that simply allows use of the class name,
> or is the "::class" suffix necessary to resolve some ambiguity? Example
> usage:
>
>    $mock = $this->getMock(A\Namespaced\**ClassName);
>    # or
>    use A\Namespaced\ClassName;
>    $mock = $this->getMock(ClassName);
>
> Would changing the definition for class_name_scalar be sufficient?
>
>    class_name_scalar:
>        class_name { zend_resolve_class_name(&$1, ZEND_FETCH_CLASS_GLOBAL,
> 1 TSRMLS_CC); $$ = $1;  }
>    ;
>
> To my eye, this is the least surprising syntax.
In your above example ClassName could just as well be a constant :)

Nikita

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
> Would changing the definition for class_name_scalar be sufficient?
>
> class_name_scalar:
> class_name { zend_resolve_class_name(&$1, ZEND_FETCH_CLASS_GLOBAL,
> 1 TSRMLS_CC); $$ = $1; }
> ;
>
> To my eye, this is the least surprising syntax.

As far as I can tell, this rule will not compile as it conflicts with
other rules, namely around the namespace implementation rules.

Besides that though, an original design goal was to implement it closer
to how other languages solve the same-ish problem. This solution is
somewhat in line with Java (.class) and Ruby (.class.name), Python
actually uses the same but instead of .class, they use .__class__.__name__

-ralph


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
> "class" won't collide anyways, as it's already a keyword, and you can't use it
> in your constant or function names. __CLASS__ has bad connotations for me, as it
> resolves to the declaring class normally, not the class invoked.

I tend to agree. __CLASS__ to me belongs to the family of constants
like __DIR__ and __FILE__ where they are meant to be evaluated in-place
and are simply a substitution for something completely static.

In my mind, while Foo::class returns a scalar, it is subject to
resolution by use statements generally at the top of a file or namespace
declaration and is computed based on what namespace it is in and what
use statements affect it.

-ralph


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Hi!

> Fantastic question. I am unsure how to handle this. Currently, it will
> simply resolve those names against the rules (I am sure this is the
> wrong behavior.) So,
>
> namespace Foo\Bar { var_dump(self::class); }

This should produce an error outside of class context, I think. Inside
of class context, self & parent should work, I think, but static can't
work as it's caller-dependent.

--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Hi!

> I tend to agree. __CLASS__ to me belongs to the family of constants
> like __DIR__ and __FILE__ where they are meant to be evaluated in-place
> and are simply a substitution for something completely static.

But that's exactly what Foo::class is - completely static constant.

> In my mind, while Foo::class returns a scalar, it is subject to
> resolution by use statements generally at the top of a file or namespace
> declaration and is computed based on what namespace it is in and what
> use statements affect it.

In the same vein you could say class statements affect __CLASS__ :).
They are both compile-time constants.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php
Sorry, only registered users may post in this forum.

Click here to login