PHP static methods - php

I understand that static methods have no access to state of instance objects of their class types and hence referencing $this inside them results in an error.But objects can reference static methods using object to member operator ->
$obj->staticMethod();
and can even pass it their state via paramaters.
$para1 = $obj->para1;
$para2 = $obj->para2;
$obj->staticMethod($para1, $para2);
How is this last example possible when statics are resolved in static context. If someone can explain to me the general behaviour of statics in php code. you can even talk about C related concepts if it will help.

Since you state that you already understand what static means, I'll skip over that.
However, it may still be good to reference PHP's documentation on the static keyword. In particular the following two alerts are important (and hard to glance over, really).
Caution In PHP 5, calling non-static methods statically generates an E_STRICT level warning.
And this one (italic emphasis mine).
Warning In PHP 7, calling non-static methods statically is deprecated, and will generate an E_DEPRECATED warning. Support for calling non-static methods statically may be removed in the future.
So, to cut a long story short: yes, your example will run (for now), because the PHP interpreter will try to fix up your mistake for you. You should however never do this. What the PHP interpreter will do is:
Say your $obj is of type Foo. Then it will read
$obj->staticMethod($para1, $para2);
conclude that staticMethod is static and instead execute
Foo::staticMethod($para1, $para2);
It is of course perfectly fine to pass parameters that are properties of an instance of Foo. It doesn't matter to staticMethod where the parameters come from.
To elaborate a bit more on why this works, while using $this in a static method is not allowed.
You can think of normal methods as static functions that have one extra: they receive an implicit parameter $this. The value of $this is simply the object on which the method is called. Thus, $obj->do($a, $b, $c) is equivalent to calling Foo::do($obj, $a, $b, $c) and naming the first argument of do, $this. This is convenient, because we can now easily define methods that work on an instance of an object without having to explicitly state over and over again that this instance is a parameter of our methods. Great.
Now back to static functions. The only difference with normal methods is that they do not receive this implicit $this parameter. Thus, using $this inside of them is invalid. Not because it is forbidden, but because it does not reference anything. PHP does not (and cannot) have a clue what $this should refer to.
Another way to look at it. Say that our Foo class has two properties: $para1 and $para2, both numbers. Say that you write a method that returns the sum of these numbers. One way is to do this:
public static function sum($para1, $para2) {
return $para1 + $para2;
}
Great. Works. However, it is annoying to have to call it like this
$sum = Foo::sum($obj->para1, $obj->para2);
So, this is what methods are for!
public function sum(/* implicit $this parameter */) {
// write looking up the properties once inside the function, instead
// of having to write it every time we call the function!
return $this->para1 + $this->para2;
}
// ...
$sum = $obj->sum(); // $obj is passed implicitly as $this
Because static functions do not receive an implicit $this parameter, using $this inside of them is like trying to use $undefined when you have never defined it. Thus, invalid.

Static means class members in simple terms , A static data member is accessible within a class regardless object is created or not . The static function are also functions dedicated to whole class . Static function works with static data only bit it can sometimes vary . Though statics are class dedicated, you can access them using object. It is allowed in all languages. Why ? Because of feasibility . If an object is not being able to access static members , that is a limitation.

Related

Method invocation in PHP

I have TestClass and a public method in it.
I am able to call the same method using :: operator like static method and using an object.
What are the advantages or use of static functions in PHP, if we able to call public functions without creating object of the same class?
<?php
class TestClass {
public function testMethod() {
echo 'Method called';
}
}
TestClass::testMethod();
$classObj = new TestClass();
$classObj->testMethod();
?>
In this case, there is no difference.
However, the point of static functions is to say that some functions don't need an instance of the class in order to be executed. It is possible to call functions statically even if they are not marked as static, but it is technically incorrect to do so. If you have error_reporting(E_ALL) set, it will give you a strict standards error.
This is not because the code won't work, but because it might not.
class TestClass {
private $name = 'Rakesh';
public function doSomething() {
echo "Hi there";
}
public function doSomethingElse() {
echo "Hi there " . $this->name;
}
}
You can call the first function statically and it will work fine. But if you call doSomethingElse statically, it won't work, because it tries to access $this, which is only possible if you have an object.
So we apply the static keyword to doSomething to let (a) PHP and (b) the programmer using the class know that it is possible to call it statically. It's a promise that it will work.
The assumption should be that, if it is not marked as static, you shouldn't call it statically.
PHP's strict standards errors are meant to make your code better, even if it already works. The documentation for the E_STRICT constant says:
Enable to have PHP suggest changes to your code which will ensure the best interoperability and forward compatibility of your code.
In low-level terms, a static function in PHP isn't much different than a member function. The only real difference is that $this isn't provided to a static function.
That means the use of the static keyword is mostly of semantic benefit, as it helps you define the architecture and intended behaviour of your classes.
With that said, you shouldn't abuse the semantics. PHP can (optionally) warn you about those kinds of mistakes, and you should always pay attention to such warnings. The language specification is there for a reason, and it's designed to work in certain ways. If you use static (or any other language feature) incorrectly, then it may not always work as you expect. Future PHP updates or configuration changes could break your code unexpectedly.
Declaring class properties or methods as static makes them accessible without needing an instantiation of the class. A property declared as static can not be accessed with an instantiated class object (though a static method can).
For compatibility with PHP 4, if no visibility declaration is used, then the property or method will be treated as if it was declared as public.
Advantages are ...
1>Hash memory will not create ,hence no wastage of Memory (no memory leak problem)
2>
// This makes little sense
Math m = new Math();
int answer = m.sin(45);
// This would make more sense
int answer = Math.sin(45);
It's like a shortchut, one feature more of php. But, to access to their properties you must declare them like constants. For example:
<?php
class Math{
const pi=3.1416;
}
echo Math::pi;
?>

__call catches static method calls

I'm using both the magic methods _call and _callStatic for my own implementation of something like an ORM/Activerow. They're mainly meant for catching certain function calls: __call is responsible for getters and setters, and __callStatic for findBy methods (e.g. findById).
To map foreign keys, i'm trying to convert calls to e.g. getArticle to return the value of Article::findById(). To do that, i'm using this case inside my __call:
if (strstr($property, "_id")) {
return $foreignClass::findById($this->getId());
}
where $property is the substring after set or get in __call, and $foreignClass the rest of the string. So, in the case of the call getArticle, $property would be get and $foreignClass would be Article.
I've placed some echoes to ensure that the values are correct. However, my __call method gets called instead of my __callStatic. If i make an implicit static method findById, it does get called (so it does recognize it as a static call). If i specifically call Article::findById(), __call also catches it.
Is this an error with the relatively new __callStatic, or am i doing something wrong?
EDIT:
The problem seems to reside in this part:
_call() is triggered when invoking inaccessible methods in an object context.
__callStatic() is triggered when invoking inaccessible methods in a static context.
Though i am calling it on a class, i am calling it from an object context. Is there a way to get into the static context in this case?
Since the code you give runs in the context of an Activity object and since the value of $foreignClas is Article, which is an ancestor of Activity, PHP assumes that you are intending to call an ancestor's implementation of the method.
To break out of the object context there is AFAIK no option other than this absolutely hideous technique:
$id = $this->getById();
return call_user_func(
function() use($foreignClass, $id) {
return call_user_func("$foreignClass::findById", $id);
}
);
The __callStatic magic method was only introduced in PHP 5.3. Prior to that, I believe static calls were routed through __call just like normal method calls. My guess would be that you are using a PHP version that is < 5.3. What is the output of php -v on the command line?

Behavior of $this on inherited methods

I always thought I understood how OOP works (and I have been using it for years), but sometimes I realize some concepts are still not so clear to me.
I just came across this question about method visibility in PHP. The accepted answer explains that a private method cannot be overridden by a child class in PHP. Okay, that makes sense. However, the example made me think about the internal inheritance mechanism in PHP, and the way $this behaves on inherited methods.
Consider this code (example from the PHP Manual, also included in the question mentioned above):
class Bar
{
public function test() {
$this->testPrivate();
$this->testPublic();
}
public function testPublic() {
echo "Bar::testPublic\n";
}
private function testPrivate() {
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar
{
public function testPublic() {
echo "Foo::testPublic\n";
}
private function testPrivate() {
echo "Foo::testPrivate\n";
}
}
$myFoo = new foo();
$myFoo->test();
/*
Output:
Bar::testPrivate
Foo::testPublic
*/
Now consider this excerpt from the PHP Manual:
The pseudo-variable $this is available when a method is called from within an object context. $this is a reference to the calling object (usually the object to which the method belongs, but possibly another object, if the method is called statically from the context of a secondary object).
The explanation states that "$this is a reference to the calling object", which is $myFoo. So I expected that $myFoo->test() would always invoke Foo::testPrivate, and never Bar::testPrivate (unless $myFoo were an instance of Bar). I tested $this with get_class, and it always returns Foo, even from inside Bar::testPrivate and Bar::test. However, $this behaves like an instance of Bar when Bar::test calls $this->testPrivate().
That's really confusing, and I am trying to understand why it works that way!
I thought inherited methods (public or protected) were somehow copied from the base to the child class. Private methods would not be copied at all. But this example indicates that it doesn't work like this. It looks like the instance of Foo keeps an internal instance of Bar, and delegates method calls to it when necessary.
I am trying to learn something here, and I only learn when things make sense to me. This one does not. After writing all this, I think I can summarize it with two questions:
Could someone briefly explain how inheritance works internally in PHP? Or at least point me to an article or documentation about that?
Is the behavior or $this discussed here present on other OO languages as well, or is it particular to PHP?
Inheritance in PHP works the same way it does in most object-oriented languages.
When you have a "virtual" method, the method is not bound directly to the caller. Instead, every class contains a little lookup table which says "this method name is bound to that implementation". So, when you say $this->testPublic(), what actually happens is that PHP:
Gets the virtual table for the current class
Looks up the virtual table entry for testPublic in that table
Invokes the method to which that lookup points
Since Foo overrides testPublic, its virtual table contains an entry for testPublic pointing to Foo::testPublic.
Now, with the private methods, the behavior is different. Since, as you correctly read, private methods cannot be overridden, calling a private method never results in a virtual table lookup. That is to say, private methods cannot be virtual and must always be defined in the class which uses them.
So, the effect is that the name is bound at the time of declaration: all Foo methods will call Foo::testPrivate when they say $this->testPrivate, and all Bar methods will call Bar::testPrivate.
To sum up, saying that "inherited methods are copied to the child" is not correct. What actually happens is that the child begins with its method-name-lookup-table being populated with its parent class' entries, and then adds its own functions and replaces any overridden entries. When you call $this->something, this lookup table is consulted for the current object's class. So if $this is an instance of Foo, and Foo overrides testPublic, you get Foo::testPublic. If $this is an instance of Bar, you will get Bar::testPublic.
Well, private methods and properties are exactly that - private. For all intents and purposes, you can consider them "internal", meaning internal to the class they're defined in. This means that they're never inherited, and can never be overridden.
Thus, when using $this in combination with a private method or property, it will always be the method or property within the same class as the reference to $this. This happens because $this called within a parent class cannot access private methods or properties in another class (because they're private), even from child classes.
Hope this helps.

How to define constant in class constructor?

Can I define a class constant inside the class constructor function ?
(based on certain conditions)
That goes against the idea of class constants - they should not be dependent on a specific instance. You should use a variable instead.
However, if you insist on doing this, are very adventurous and can install PHP extensions, you can have a look at the runkit extension that allows to modify classes and their constants at runtime. See this doc: http://www.php.net/manual/en/function.runkit-constant-add.php
I don't think you can.
It wouldn't make sense, either - a class constant can be used in a static context, where there is no constructor in the first place.
You'll have to use a variable instead - that's what they're there for.
Try look here:
http://php.net/manual/en/language.oop5.constants.php
http://php.net/manual/en/language.oop5.static.php
Hope this helps.
As far as standard instance constructors go, there is no way to do this, and as others have pointed out, it wouldn't make sense. These constructors are called per created object instance, at the point they are created. There is no guarantee this constructor would get called before some code tried to access the constant. It also doesn't make sense in that the code would get called over and over again each time a new instance was constructed, whereas a const should only get set once.
It would be nice if PHP either offered some kind of static constructor that let you set the value one time for uninitialized constants, or allowed more types of expressions when defining constants. But these are not currently features of PHP. In 2015 an RFC was made that proposed adding static class constructors, but it is, at the time of me writing this answer, still in the draft status, and has not been modified since 2017.
I think the best alternative for now is to not use constants in this kind of scenario, and instead use static methods that return the value you want. This is very simple in that it only uses the PHP language features as is (not requiring any special extensions), these static methods can be called in the standard way, and you don't need to hack the autoloading process to call some kind of initializer function that sets static variables. The method might need to rely on private static variables in order to make sure the same instance is returned every time, if an object instance is being returned. You would need to write the implementation of this method to be constant like in the sense that it will always return the same thing, but takes advantage of being able to do things you can't do with a constant, like return on object instance or rely on complex expressions or function calls. Here is an example:
final class User
{
/** #var DefinitelyPositiveInt|null */ private static $usernameMaxLength;
public static function getUsernameMaxLengthConst(): DefinitelyPositiveInt
{
if ($usernameMaxLength === null) {
$usernameMaxLength = new DefinitelyPositiveInt(40);
}
return $usernameMaxLength;
}
}
$usernameInput.maxLength = User::getUsernameMaxLengthConst();
This is still not a perfect solution because it relies on the programmer to write these in a constant like way when that is desired (always returning the same value). Also, I don't like that the best place to document the fact that it is a const is in the method name, thus making it even longer to call. I also don't like that you now have to call it as a method instead of just accessing a property, which would be syntactically nicer.
This example is essentially an implementation of a singleton, but sometimes the purpose of a singleton is to be a constant rather than just a singleton. What I mean is, you might want the instance to always exist, and it might be an immutable type (none of the properties are public or mutable, only having methods that return new objects/values).
I am sorry to break it to you but it is not possible in vanilla PHP.
I am not very sure about frameworks or extensions but I am sure that it is not possible in vanilla PHP.
I recommend you to use variables instead.
You still can't, but maybe some of these (progressively weirder) ideas (just ideas, not true solutions) will work for you:
(1) You could use a private property, with a public getter method. The property cannot be modified outside the class, such as constants, but unfortunately it is accessed as a method, not as a constant, so the syntax is not the same.
class aClass{
private $const;
function __construct($const){
$this->const=$const;
}
function const(){
return $this->const;
}
}
$var1=new aClass(1);
echo $var1->const(); //Prints 1
(2) If you really want this value to be accessed as constant from outside, you can use define () inside the constructor. Unfortunately it doesn't get tied to the class or object name (as it do when you use const, using for example myClass::myConst). Furthermore, it only works if you create a single instance of the class. The second object you create is going to throw an error for redefining the constant, because is untied.
class otherClass{
function __construct($const){
define('_CONST',$const);
}
function const(){
return _CONST;
}
}
$var2=new otherClass('2');
echo $var2->const(); //Prints 2
echo _CONST; //Prints 2
#$var3=new aClass('3'); //Notice: Constant _CONST already defined
echo _CONST; //Still prints 2!
(3) Perhaps that last problem can be solved by giving variable names to the constants, related to the object to which they belong. This may be a bit weird... but maybe it works for someone.
class onemoreClass{
private $name;
function __construct($const,$name){
$this->name=$name;
$constname=$this->name."_CONST";
define($constname,$const);
}
function const(){
return constant($this->name.'_CONST');
}
}
$name='var4';
$$name=new onemoreClass(4,$name);
echo $var4->const(); //Prints 4
echo var4_CONST; //Prints 4
$name='var5';
$$name=new onemoreClass(5,$name);
echo $var5->const(); //Prints 5
echo var5_CONST; //Prints 5

PHP and Static Variables in Object Member Functions

Up until today, I thought I had a fairly good grasp of how the static modifier worked. I know that (in laymans terms) a static variable in a function does not 'reset' across calls to that function, and I know that static variables and functions on a class are accessible by calling upon them through the class itself (not an instantiation of the class).
My problem is this: today I found that if I declare a static variable inside of a non-static function on a class, all instantiations of that class share that static variable in separate calls to the member function.
For example:
class A {
public function GetValue() {
static $value = 0;
$value++;
return $value;
}
}
$instance_1 = new A();
$instance_2 = new A();
echo $instance_1->GetValue();
echo $instance_1->GetValue();
echo $instance_2->GetValue();
echo $instance_2->GetValue();
echo $instance_1->GetValue();
echo $instance_1->GetValue();
Notice that the GetValue function is neither declared as static or used in a static way (as in, called on the class itself).
Now, I always assumed that this would output: 121234
Instead, I find that it will output: 123456
Like I say, I would understand this if the static variable $value was inside of a static function. However, with it being inside a non-static function I just assumed that it would only be 'tied' to the function 'within' each individual instantiation.
I guess my question is twofold, then... 1) is this a bug or expected behaviour? 2) do other languages treat these 'static inside non-static' variables the same way, or is this unique to PHP?
This is expected.
This is also the case in C++ (and probably others as well).
You should think of non-static class member functions as if they were just like ordinary functions, but with an implicit $this argument that is automatically provided by the interpreter. (That's exactly how they're implemented in most languages.)
I've copied the following information from this article by Josh Duck: http://joshduck.com/blog/2010/03/19/exploring-phps-static-scoping/
Static variables have been available since PHP 4 and allow you to define a persistent variable that is only accessible from the current function. This allows you to encapsulate state into a function or method and can eliminate the need for classes where a single function will suffice.
When a static variable is defined inside a class method they will always refer to the class on which the method was called. In doing this they act almost like properties referenced through static, though there are subtle differences.
Static variables can’t preserve the calling class scope. This can be potentially problematic if you have an inherited method containing a static variable that is called from both inside and outside its class.
As far as I know, all languages with static variables treat them this way. Think of static variables as global variables that can only be accessed from a certain scope.

Categories