I don't know if "declaration" is the right word for what I'm asking. It might be "definition" or something else.
PHP does not declare variables. You just define them by assigning a value.
But there are certain keywords that declare the existence of a new entity: const, function, class, and interface. They all have the same syntax:
keyword EntityName code
as in
const ConstantName = 1;
function FunctionName {...}
class ClassName {...}
interface InterfaceName {...}
I don't see anywhere in the PHP Manual where these keywords are discussed together but they definitely seem to play a kind of top-level role in the language. Each of them is documented in their own respective sections of the manual, but I wonder if there's a useful way to think about them in terms of the analogous roles they play. And are there other keywords in that category besides those four? Is there any combined documentation about them?
Despite PHP is a "weak type" language (so you can't declare variable types), PHP7 strenghtened the type protection (if strict_types is set to 1).
You can't declare a type in lines of code but you can asset them within functions declaration.
i.e.
function myfunction(float $a, float $b) : int {
return $a + $b;
}
Please note that we are declaring $a, $b types and the return type.
Another feature that allows you to "declare" variable types is the "new" operator (as many other OOP languages). With "new" you will instantiate your classes and this will never vary unless you perform a dynamic binding or casting.
Just to clarify the concepts you mention:
const : Declare a class constant (From PHP 5.3 you can use const outside classes also).
function: Classical PHP function/method declaration. PHP7 allows you to set parameter types and return types.
class : Class declaration.
interface: Interface declaration (special base class definition that can't have any implementation without inheritance).
Some useful resources for beginners.
(PHP7 OOP)
http://www.brainbell.com/tutorials/php/php7-oop-beginners.html
http://php.net/manual/en/reserved.keywords.php (from #Jacin comment)
(PHP7 types)
https://www.tutorialspoint.com/php7/php7_returntype_declarations.htm
http://blog.teamtreehouse.com/5-new-features-php-7
Related
Basically the purpose of the static keyword is totally clear to me, the PHP docs only explain the purpose of the keyword in the context of classes. I noticed one of my IDE plugins suggesting me that I should declare many of my callback functions as static.
Without static:
$myUniqueArray = unique($arrayToFilter,
function (ExamQuestion $examQuestion) {
return $examQuestion->getId();
}
);
With static:
$myUniqueArray = unique($arrayToFilter,
static function (ExamQuestion $examQuestion) {
return $examQuestion->getId();
}
);
For the result it does not make a difference, it works both. What exactly is the difference between a callback function and a static callback function in PHP under the hood? What are possible benefits and drawbacks in this context?
You're referring to Static Anonymous Functions [DOC] which are introduced as following in the documentation:
Anonymous functions may be declared statically. This prevents them from having the current class automatically bound to them. Objects may also not be bound to them at runtime.
If you compare that with the explanation of the static keyword in the context of class methods [DOC], this might make the relation more clear. These are introduced as following in the documentation:
Because static methods are callable without an instance of the object created, the pseudo-variable $this is not available inside methods declared as static.
So an actual difference is that you don't have $this bound / available within the anonymous function when it is static.
The reason why you get the suggestion within the IDE is that static anonymous functions give you a slightly better performance over the non-static variant. So unless you need $this within the function, you can safely use the static variant over the non-static one.
Anonymous functions have been introduced in PHP 5.3 [RFC] [5.3.0], with the addition of the static keyword in PHP 5.4.
In PHP 5.3 $this was not automatically bound when defined within a class (intentionally) which has been changed with PHP 5.4 and it is since then that $this is automatically bound for the (non-static) anonymous function.
Since PHP 7.4 you can find arrow functions [DOC] which also come in the static/non-static flavours. However:
Arrow functions support the same features as anonymous functions, except that using variables from the parent scope is always automatic.
It's not only $this that a (non-static) arrow function would bound, it is (even for static ones) that all variables from the parent scope are automatically in use when in use. So this may hit performance more than given the occasional benefit of static for anonymous functions.
NOTE: This is not only theoretical (you need to measure for performance comparisons) but it might also create the impression that all outer scope variables might be bound in the (static) arrow function. But, only those which have a literal variable expression (e.g. $var), not variable variables, not even superglobals but this (which errors in static context and therefore even if it might be bound there as well it would be useless), are available in the arrow function expression. You can safely use static over not using it with arrow functions as well if you're not making use of $this in the arrow function expression (just to make it explicit again with this answer).
As you haven't shared which IDE, it is only a guess to which concrete suggestion you're referring to. Our educated guess is Phpstorm with the EA inspections plugin:
[EA] This closure can be declared as static (better scoping; in some cases can improve performance).
From the Static closures can be used EA inspection. And with the further information:
Analyzes closures and suggests using static closures instead.
This can bring additional performance improvements, e.g. as here:
Also, by using static function () {} closures, we squeezed out another 15% of hydration performance when dealing with private properties.
(from the inspection description provided by Php Inspections (EA Ultimate) within Phpstorm)
The accpted answer by hakre is very informative but I think it is wrong in one point.
The performance of static arrow functions and static anonymous functions is the same:
This:
$x = 123;
static function () { return true; }
is as performant as this:
$x = 123;
static fn() => true;
The accepted answer assumes that the arrow function is slower because $x is always captured by-value in the arrow function. This is not true because if $x is not used (like in my example) then it is not captured by-value. I tested it by simply using PHP's get_defined_vars().
I know there are a couple of similar questions here in StackOverflow like this question.
Why is overriding method parameters a violation of strict standards in PHP?
For instance:
class Foo
{
public function bar(Array $bar){}
}
class Baz extends Foo
{
public function bar($bar) {}
}
Strict standards: Declaration of Baz::bar() should be compatible with
that of Foo::bar()
In other OOP programming languages you can. Why is it bad in PHP?
In OOP, SOLID stands for Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion.
Liskov substitution principle states that, in a computer program, if Bar is a subtype of Foo, then objects of type Foo may be replaced with objects of type Bar without altering any of the desirable properties of that program (correctness, task performed, etc.).
In strong-typed programming languages, when overriding a Foo method, if you change the signature in Bar, you are actually overloading since the original method and the new method are available with different signatures. Since PHP is weak typed, this is not possible to achieve, because the compiler can't know which of the methods you are actually calling. (hence the reason you can't have 2 methods with the same name, even if their signatures are different).
So, to avoid the violation of Liskov Substituition principle, a strict standard warning is issued, telling the programmer something might break due to the change of the method signature in the child class.
I know I am late to the party but the answers don't really spell out the actual problem.
The problem is PHP doesn't support function/method overloading. It would be difficult to support function overloading in an untyped language.
Hinting helps. but in PHP it is very limited. Not sure why. For example you cannot hint a variable is an int or Boolean yet array is fine. Go figure!
Other object orientated languages implement this using function overloading. Which is to say the signature of the function is obviously different.
So for example if the following was possible we would not have an issue
class Foo
{
public function bar(Array $bar){
echo "Foo::bar";
}
}
class Baz extends Foo
{
public function bar(int $bar) {
echo "Baz::bar";
}
}
$foo = new Baz();
$bar = new Baz();
$ar = array();
$i = 100;
$foo->bar($ar);
$bar->bar((int)$i);
would output
Foo::bar
Baz::bar
Of course when it came to constructors the php developers realised they have to implement it, Like it or not! So they simply suppress the error or not raise it in the first case.
Which is silly.
An acquaintance once said PHP implemented objects only as a way of implementing namespaces. Now I am not quite that critical but some of the decisions taken do tend to support that theory.
I always have maximum warnings turned on when developing code, I never let a warning go by without understanding what it means and what the implications are. Personally I don't care for this warning. I know what I want to do and PHP doesn't do it right. I came here looking for a way to selectively suppress it. I haven't found a way yet.
So I will trap this warning and suppress it myself. Shame I need to do this. but I am strict about STRICT.
You can override parameters, but the signature should match. If you had put Array out in front of $bar, there would be no problem.
For example, if you had added an additional parameter, there would be no problem, provided the first parameter had the same type hinting. This is good practice in any language.
Because you declared on Foo that $bar should be of type array, while in the extending Bar, $bar's type isn't declared.
This isn't an error, it's a warning. You should make the method definition compatible with the original, base class. You can, however, safely ignore it if you know what you're doing (and only if you know what you're doing!!!)
while studying oop in PHP, I noticed that the property declaration accepts an array as value as mentioned here PHP documentation
class Test{
public $var7 = array(true, false);
}
and I noticed that the documentation says :
This declaration may include an initialization, but this initialization must be a constant value--that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.
and after reading this article to know how the compilation process works, I realized that within the compilation process, some expressions would be evaluated and optimized if it possible like the below snippet :
var x = strlen ("testing") => int(7);
if using the array as a value in declaring property worked because it's evaluated in the compilation process, then why did not the below initialization work if logically both of them could be evaluated at the compilation process and this is the condition to initialize a property in a class?
Class Test {
public $vars=strlen("random"); // Fails
}
The short answer to your question is that strlen() is a function while array() is a keyword.
The critical difference to understand is that keywords always reference the same thing regardless of context.
From php.net:
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 names.
Functions, on the other hand, could be defined differently depending on where you are calling them.
Consider this simplistic example:
First a file we'll call "functions.php".
//functions.php
namespace My_Project_Namespace;
function strlen($string){
return 10; //In my project, all strings are length 10! 10 is a nice round number...
}
In this file, I am overriding the built-in strlen() function with another one. This is possible because my function is defined inside a namespace (in this case, My_Project_Namespace).
Now consider your file, but this time let's put it in our namespace (you should be name-spacing all your functions and classes)
//Test.php
namespace My_Project_Namespace;
Class Test {
public $vars=strlen("random"); // Fails
}
strlen() has 2 definitions depending on the namespace. Since knowing the current namespace depends on runtime information the compiler cannot know which to use for initialization in the class. Even if you didn't define a custom strlen() function you still couldn't do this because knowing that there isn't another version strlen() also depends on runtime information!
array() is a totally different beast. It is a keyword, you cannot define another meaning for array() so the compiler doesn't have to worry about one existing.
I've always used annotations to declare return type. For example:
/**
* #return SomeClass
*/
public function () { ... }
But now I see there's another way:
public function () : SomeClass { ... }
Question
Should I be choosing between these, using both, or do they have some fundamental difference I should be aware of?
According to me you should use both when possible.
Adding return type of function in PHP (possible from PHP 7) is useful to ensure type during execution. Note that PHP 7 allow supports parameters type in function.
Adding annotation above function is useful to generate documentation. Example PHPDocumentor uses annotation, like #return.
Annotation has nothing to do with return type. It will not throw any error or warning if you are returning something else. Although it's helpful for documentation.
Apart from that the other method is php7 Return Type Declarations which support all the same types as arguments. To specify the return type, we add a colon and then the type right before the opening curly bracket.
Strict typing also has an effect on return type declarations. In the default weak mode, returned values will be coerced to the correct type if they are not already of that type. In strong mode, the returned value must be of the correct type, otherwise a TypeError will be thrown.
Adding the return type allows you to to be sure your function returns what is expected as well as making it easy to see upfront how the function works.
NOTE :
When overriding a parent method, the child's method must match any
return type declaration on the parent. If the parent doesn't define a
return type, then the child method may do so.
There is some degree of overlap between these.
Unlike type annotations, type declarations are part of the language itself, and enforced by the language runtime. If you use a type declaration to specify that a function takes (or returns) an int, and you pass in (or return) an array, you'll get an error. If you pass in a float, PHP will try to convert it for you if possible and error otherwise (weak mode), or always throw an error (strict mode). Type declarations are also checked in inheritance and when implementing interfaces, preventing you using the wrong types in your implementations. Annotations, on the other hand, are merely comments and are not enforced by the runtime. Because type declarations are enforced, you would ideally always use them where possible.
Since both type annotations and type declarations can serve as documentation of a parameter or return type, an annotation is redundant if you have a type declaration. But bear in mind whether you are using tools, such as an IDE or documentation generator, that don't recognise type declarations yet, and would need you to retain the annotations. You should also consider that you can provide a description of a parameter or return value in an annotation for documentation, which you can't do with a type declaration, and there are also sometimes cases where you can specify a more precise type in an annotation (e.g. int[] annotation vs array declaration, or a subclass of the class returned by the method you are overriding). However, if neither of these apply, and your annotations provide no more information than is in the function signature (the function foobar(int $foo, string $bar): Qux line), annotations are a waste of space.
So, in summary: always use type declarations. As for annotations, use them if you need to (tooling) or they provide additional information.
I have a class in which I want to define some constants used by other classes. The const keyword isn't enough for me because I want for example to use a mathematical expression like 2.0 * pi() as a constant. How is done?
I understand you want to assign a mathematical expression to a constant.
Like:
const FOO = 2.0*pi();
PHP constants can only contain scalar values. If you want other classes to use shared information, you will have to use static functions/methods for this.
Example:
static public function foo()
{
return 2.0*pi();
}
Actually something similar is implemented in PHP 5.6 where you can assign results of various expressions to class constants.
You can read more about it here:
http://php.net/manual/en/migration56.new-features.php#migration56.new-features.const-scalar-exprs
and here:
https://wiki.php.net/rfc/const_scalar_exprs
Assigning results of functions is still not allowed according to the documentation, however the following expression that has the same result as your example should be completely valid:
const FOO = M_PI*2;
Be advised that PHP 5.6 does not have a stable release yet, so it is not recommended for now to use it in production.