-
Notifications
You must be signed in to change notification settings - Fork 7.9k
add nameof operator #11172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
add nameof operator #11172
Conversation
This most certainly requires an RFC. The RFC process is described at: https://wiki.php.net/rfc/howto. Would you be willing to pursue your proposal with the RFC process? |
I sent a discussion email per the RFC at the same time as this PR: https://externals.io/message/120173 |
@TimWolla just out of curiosity and a feeling of foreboding after nearly a week of waiting:
Did I fall through some cracks, did I do something wrong, or is this a way of saying "We're not interested?" |
There is a very limited number of folks that are able to grant the necessary permissions (we should change that) and I am not able to grant the permissions. I've already asked in your behalf in StackOverflow chat, but did not receive a response either.
This doesn't necessarily surprise me, the proposal is pretty clear and some folks probably will only comment on the real discussion to not unnecessarily split it into several locations. |
Thanks @TimWolla, it's good to know there is something happening somewhere. I'll patiently wait and maybe bug the list again in another day or two. |
@withinboredom You should have karma now. |
zend_ast *var_ast = ast->child[0]; | ||
zend_ast *name_ast; | ||
|
||
// todo: proper error handling and better error messages |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are your ideas for proper error handling? Happy to thinker with you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MelvinRook, I'm actually still trying to come up with something in the RFC that makes sense (and will probably come up in discussions). For example, should this be an error and what might the error message be:
$x = null;
unset($x);
echo nameof($x);
In this specific implementation, no error/warning message is shown if you use a non-existent variable/method/member/etc, nor is any autoloading triggered. This might be desired for performance/optimization reasons, but the entire point is to make refactoring of messages/strings easier, thus inconsistencies could be missed.
If a message is emitted, what should be emitted? Notices, warnings, errors, exceptions? I personally, would favor a normal message, so the above would emit a warning ("Undefined variable $x in ...") but I can see how other people might want something special to happen.
Lots to think about and I haven't particularly settled on any particular implementation. I'd love to hear any arguments for any of them.
break; | ||
default: | ||
zend_error_noreturn(E_COMPILE_ERROR, | ||
"Cannot use nameof() on the result of an expression or something with an ambiguous name"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can "something" be more specific in this error, or is it as specific as it can be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes and yes; that's actually a good question. I imagine that given more examples, more helpful error messages can be created, but there are "somethings" that are ambiguous or don't make sense:
echo nameof($a['b']);
echo nameof(empty($x));
echo nameof($x === $y);
echo nameof('literal');
In the grammar, I chose an expression as what can go in the brackets/parenthesis, but it doesn't make sense to accept literally any expression. Perhaps there is something better to use (or construct), but I didn't want to spend too much time on it in case there was a name for these more ambiguous things that I don't have the imagination for.
Instead of a function, wouldn't something like echo $variable::name; // variable
echo ${$variable}::name; // variable
echo $object->property::name; // property
echo Object::$property::name; // property
echo Enum::Case::name; // Case
echo Object::Const::name; // Const
echo myFunction()::name; // myFunction
echo MY_CONSTANT::name; // MY_CONSTANT etc. |
Thanks for your feedback @sybrew, but there's one issue that precludes that syntax from actually working: ambiguity. For example, let's start with some code: class Test
{
public const name = 2;
public function __construct()
{
echo 'hello world';
}
}
echo Test::name; In your proposal, what should the output be? The reason class Test
{
public const class = 2; // <---- syntax error
public function __construct()
{
echo 'hello world';
}
}
echo Test::class; Second, the Thirdly, "better" is purely subjective. I think |
Forgive my ignorance, but... Something like: class Template {
// ...
public function use (...$vars) {
$var_names = [];
foreach ($vars as $var) {
$var_names[] = nameof($var);
}
// $var_names[0] = 'foo'
// $var_names[1] = 'bar'
}
// ...
}
$Template = new Template;
$foo = "bar";
$bar = 'barz';
$Template->use($foo, $bar); I believe that it currently works by taking the literal name of $var which is 'var', but is it possible, already inside the function, to get the name of the variable that was passed in the function's argument? |
Yes,
|
An interesting addendum would be to allow this: $Template = new Template;
$foo = "bar";
$bar = 'barz';
$Template->use(nameof($foo): $foo, nameof($bar): $bar); Though it would be simpler to just: $Template = new Template;
$foo = "bar";
$bar = 'barz';
$Template->use(...compact(nameof($foo), nameof($bar))); It'd be nice to create a better syntax than |
Any updates? This would be a nice feature to have. |
Heh, good timing @user451421541757324 (love the username btw). I plan on putting this to a vote early next month and reintroducing it to the list some time in the next few days -- after rebasing this PR and fixing a few minor bugs. |
Great news, thanks a lot for your work. |
After seeing some discussions about using enum values as keys, I thought of my own implementation of
nameof
(from C#) that is very hackish: https://github.com/withinboredom/nameofI'd like to propose making it a real thing (with better behavior than my hack). An operator like this has a few niche uses, mostly for better error messages but also for making strings of things that you normally can't get the string value of. Here are some examples:
nameof(func(...)) === 'func'
nameof($party) === 'party'
nameof($captain->planet) === 'planet'
nameof(Class::Prop) === 'Prop'
I first attempted this as an extension, but this belongs at the parsing/compiling level and not during runtime (this gets turned into a constant zval).
I use my (very hacky) implementation to handle stringifying enums (mostly), as well as better, easier-to-refactor error messages:
throw new InvalidArgumentException(nameof($var) . ' has an unexpected value');
Without it, the name of the variable can be missed in a refactor, making the error message useless or incorrect.
The code to make this possible (without much error checking) is relatively simple