The double colon (::) is the Scope Resolution Operator.
This is used to access protected methods and properties (and constants).
However, I have seen the use of ::class to return the string representation of the class. Like so:
namespace App;
class MyClass
{
}
var_dump(MyClass::class); # string(11) "App\MyClass"
I have searched far and wide for a documentation over this behaviour.
Is the above code also using the Scope Resolution Operator or is this something completely different? If so, what is the name of it?
If it is using the SRO, does that mean that PHP places a static property "class" behind the scenes? (I have been unable to override this static property though)
This is a new feature in PHP5.5, see: http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class
It's basically for getting the full class name. It's also not a static variable (see no preceding $) but a language feature using the class keyword. As per the note on php.net:
The class name resolution using ::class is a compile time transformation. That means at the time the class name string is created no autoloading has happened yet. As a consequence, class names are expanded even if the class does not exist. No error is issued in that case.
The operator ::class was introduced with PHP 5.5 and returns a string with the fully qualified class name.
Related
Essentially, I seek to pass a static class method to a callback, but do not wish to do so using a hard-coded string, but rather the fully-qualified class method literal. We can do that using classes like so:
$name = NS\FooClass::class;
instead of:
$name = 'NS\FooClass';
which will give us the string of the fully-qualified name of the class. I seek to be able to do something similar for a class method like so:
$name = NS\FooClass::foo_method::method;
instead of:
$name = 'NS\FooClass::foo_method';
It is more manageable and I can use the IDE functionality way better using the literals. Any similar way I can achieve what I want with the class methods without using strings?
There is currently no such mechanism built into the language. It has been suggested - see for instance this discussion from Feb 2020 - but there are more nuances to think about than might be immediately apparent; notably:
Should the syntax resolve at run-time and check the existence of the class and the method (::class in most cases doesn't; a bare function like strlen::func would have to because of the way namespaces resolve; an object implementing __callStatic could never be used this way)?
Should the result be a string, an array (see below), or a Closure object?
Anyway, that's a topic for elsewhere...
As the manual page on the callable type says, there are two ways to specify a static method for use as a callback:
As a string, as in your example 'NS\FooClass::foo_method'
As an array where the first part is a class name, and the second part is a the method name: ['NS\FooClass', 'foo_method']
Since only the class name needs to be qualified with namespace information, you can use ::class with the second syntax to get nearly what you wanted:
$callback = [NS\FooClass::class, 'foo_method'];
This allows any decent IDE to spot the reference to the class, and allows you to reference it by an imported or aliased name.
It's worth noting that if the callable type is specified in a parameter or return type declaration or a docblock, some IDEs (e.g. PhpStorm) will "understand" either format as a reference to the method, and include it in features like "find usages" and "go to declaration".
In PHP there are two namespacing operators:
\ and ::
:: is used for internal namespacing, e.g:
namespace example;
class Foo {
public static $bar = 'hello';
}
I can access $bar and other members of the Foo class via: Foo::$bar
The full namespaced name of Foo however is not example::Foo, it is example\Foo, and the full namespaced name of $bar would be example\Foo::$bar
What was the reason or rationale for using the two operators rather than sticking with one consistent operator that already existed?
You should take a peek at the namespace separator RFC, which calls out the actual arguments used in favor of and against the backslash.
The main reason why :: wasn't picked was due to the possible ambiguity it caused when doing scope resolution. Given that namespaces can be aliased (use \Foo\Bar as Baz;), all sorts of hilarious hijinks could be caused.
The :: is the Scope Resolution Operator and is only ment to access static classes. It has nothing to do with the namespace. Also the namespacing has been added in PHP 5.3, so long after static classes.
I guess thats why they use two different operators (for two different goals)
In PHP, call_user_func(array(self, 'method_name')) doesn't work. The self keyword cannot be used in that context. I need to actually include the name of the class call_user_func(array('class_name', 'method_name')).
However, if I'm not in a static function, the $this variable does work in that context. Why the difference?
If you want the name of the current class context, use get_class() (without any parameters) or __CLASS__.
You've already written the difference; self is a keyword, and is not usable as a reference in an array (what kind of type should that be in PHP?). get_class() returns a string, and the array()-callback supports using a string as the first name to do a static call.
You can try with __CLASS__ to get the class name. Also it may work to use call_user_func('self::method_name') directly, but I didn't test it and the documentation about callbacks doesn't say anything about this.
self is just an undefined constant, so it expresses 'self'. So these two are the same:
array(self, 'method_name');
array('self', 'method_name');
And depending on the PHP version you use, this actually works, see Demo.
In case it does not work with your PHP version, some alternatives are:
call_user_func(array(__CLASS__, 'method_name'));
or
call_user_func(__CLASS__.'::method_name'));
or (in case you don't need call_user_func):
self::method_name();
Since PHP 5.5, you can do [self::class, 'methodName'].
::class is really useful for situations where you have a class name (maybe a local alias) and you need to generate the full class name as a string.
In PHP 5.3, you can write call_user_func('self::method') or call_user_func(array('self', 'method')). I suppose the latter could work in older versions as well.
In C#, variables and other things can be named protected names such as "class" by prepending the name with an # sign. So, #class is a valid name. Is it possible to do this same thing in PHP? I am using a class of constants to simulate an enum for HTML attributes such as ID, and Class. For now I am using "CssClass" but I'd rather use the name Class somehow.
Nope, not possible, at least not for class constants.
You cannot use any of the following [reserved] words as constants, class names, function or method names.
I don't know about C#, but there isn't any special symbol in PHP to transform a keyword into an identifier. As long as you don't name it exactly the same as a keyword (barring letter case), it'll just be any normal constant name.
How about a (different since it's not just CSS) prefix? Gets repetitive to type, but is a nice workaround. I realize this may be redundant as well if your class is named something like HTMLAttribute, but it's the easiest way out.
const A_ID = 'id';
const A_CLASS = 'class';
// etc
Yes, it is possible.
In fact you can define anything as constant:
define("define", 1);
define("class", 1);
define("if", 1);
define("=.+*", 1);
However, you can not use all defined constants.
You can query them with constant("if") again. But this is not exactly what you asked for. So unlike C# there is no shortcut to use any random constant. But as for naming them, there are almost no restrictions. (Might be a bug though. It's PHP.)
Constants:
The name of a constant follows the same rules as any label in PHP. A valid constant name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thusly: [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
List of reserved keywords:
These words have special meaning in PHP. Some of them represent things which look like functions, some look like constants, and so on--but they're not, really: they are language constructs. You cannot use any of the following words as constants, class names, function or method name.
[see list here]
Within these rules you're free to make up your names. So, for instance, you could name a constant _CLASS, but not CLASS. I'd avoid the use of such ambiguous names though and namespace constants that are particular to the app, like MYAPP_CLASS.
Going from PHP5 to PHP7, a class constant could be named almost anything:
class ReservedWord
{
// Works in PHP >= 7.0 only
const NULL = null;
const TRUE = true;
}
However, thanks to this part of the manual and this comment, I've found that a class constant cannot be named these few things (see the test here):
class
static
__halt_compiler (oh, that was so useful!)
Edit: As I found in here in an RFC, the reason why class constant does not work is the name resolution ::class. However, still no idea about the two others.
class foo
{
const bar;
}
and to access it we have to do: self::bar; and not, $this->bar;
Is this correct? If so, why?
Yes this is correct. The reason is that a constant is class-bound whereas a property is instance-bound so it wouldn't make much sense to access it through a reference. No matter how many instances you create there will always only be one foo::bar const.
It's just a language design decision that it's not possible to access a const through a reference though, in Java for example you can indeed access a static final property through a reference but you will usually get a compiler warning.
Well, because they are constants that means they are static (constant and static are synonyms) and also it makes no sense in having one for each instance if they don't ever change, so you have them per class. Static members are accessed with ::.
A good point to note, which has been missed thus far is the fact that constants can contain only primitive values. They also cannot be changed once they are set, an attempt to set a value after its already declared will result in a parse error.
You should essentially use constants only when your property is needed across every instance of the class, and of course if it needs to be fixed.