Php: Static and Non Static Functions and Objects

PHP: Static and non Static functions and Objects

Static functions, by definition, cannot and do not depend on any instance properties of the class. That is, they do not require an instance of the class to execute (and so can be executed as you've shown without first creating an instance). In some sense, this means that the function doesn't (and will never need to) depend on members or methods (public or private) of the class.

PHP static methods vs non-static methods/standard functions

To call a non-static method you need to instantiate the class (use the new keyword to create a new instance of the class).

When calling a static method you don't have to "new it up" but it won't have direct access to any of the non-static properties or methods. There are dozens of use-cases / scenarios where you might want to use one over the other.

To be quite honest it has never even crossed my mind to think about performance of using one over the other. If it got to a point where it made that much of a noticeable difference (and all major steps had been taken to increase efficiency) then I would imagine that either the maintenance costs of such a big application would outweigh the need for the increased efficiency or the logic behind the app is fairly flawed to begin with.


Examples for static and non-static

If I was going to use a class for the example in your question then I would use the static version as nothing in the method is reliant on other properties of the class and you then don't have to instantiate it:

Session::start_new_session()

vs

$session = new Session();

$session->start_new_session();

Also, static properties on a class will remember state that would have otherwise been lost if you were to use a non-static property and instantiation:

class Session
{
protected static $sessionStarted = false;

static function start_new_session()
{
if (!static::$sessionStarted) {
session_start();
static::$sessionStarted = true;
}
}
}

Then even if you did:

$session = new Session();

$hasStated = $session::sessionStarted;

$hasStarted would still be true.

You could even do something like:

class Session
{
protected static $sessionStarted = false;

public function __construct()
{
$this->startIfNotStarted();
}

function startIfNotStarted()
{
if (!static::$sessionStarted) {

session_start();

static::$sessionStarted = true;
}
}
}

This way you don't need to worry about starting the session yourself as it will be started when you instantiate the class and it will only happen once.

This approach wouldn't be suitable if you had something like a Person class though as the data would be different each time and you wouldn't want to use the same data in difference instantiations.

class Person
{
protected $firstname;

protected $lastname;

public function __construct($firstname, $lastname)
{
$this->firstname = $firstname;
$this->lastname = $lastname;
}

public function getFullname()
{
return "{$this->firstname} {$this->lastname}";
}
}

//

$person1 = new Person('John', 'Smith');
$person2 = new Person('Jane', 'Foster');

$person1->fullname(); // John Smith
$person2->fullname(); // Jane Foster

If you were to use static methods / properties for this class then you could only ever have one person

class Person
{
protected static $firstname;

protected static $lastname;

static function setName($firstname, $lastname)
{
static::$firstname = $firstname;
static::$lastname = $lastname;
}

static function getFullname()
{
return static::$firstname . ' ' . static::$lastname;
}
}

//

Person::setName('John', 'Smith');
Person::setName('Jane', 'Foster');

Person::getFullname(); //Jane Foster

The debates

You are probably going to see a lot of debates over which is better and what the best practices are when it comes to PHP (not just about static and not-static methods).

I wouldn't get bogged down with it though! If you find that one side makes more sense to you (and whatever you building at the time) then go with that one. Standards and opinions change all the time in this community and half of the stuff that was a problem 5 years ago (or even less) will actually be non-issues today.

Take the Laravel framework as an example -- one of the (many) debates is that Facades are bad because they're static and make use of magic methods which is hard to test and debug. Facades are actually very easy to test and with the use of stack trace error reporting it isn't hard to debug at all.

That being said, if you find the majority of people are saying the same thing and there isn't really a debate for the other side, there is probably a reason e.g. don't use mysql_ functions or don't run queries inside a loops.

Hope this helps!

Does static method in PHP have any difference with non-static method?

Except that, if you try to use $this in your method, like this :

class t {
protected $a = 10;
public function tt() {
echo $this->a;
echo 1;
}
}
t::tt();

You'll get a Fatal Error when calling the non-static method statically :

Fatal error: Using $this when not in object context in ...\temp.php on line 11

i.e. your example is a bit too simple, and doesn't really correspond to a real-case ;-)


Also note that your example should get you a strict warning (quoting) :

Calling non-static methods statically
generates an E_STRICT level warning.

And it actually does (At least, with PHP 5.3) :

Strict Standards: Non-static method t::tt() should not be called statically in ...\temp.php on line 12
1

So : not that good ;-)


Still, statically calling a non-static method doesnt't look like any kind of good practice (which is probably why it raises a Strict warning), as static methods don't have the same meaning than non-static ones : static methods do not reference any object, while non-static methods work on the instance of the class there're called on.


Once again : even if PHP allows you to do something (Maybe for historical reasons -- like compatibility with old versions), it doesn't mean you should do it !

How to call a non-static method from a static function in a class in php

Just create an instance:

    public static function staticFun ($data) {
$instance = new ClassName($data);
echo $instance->anotherFun($data);
}

Note: you have a parameter $data for anotherFun, but you don't use it anywhere.

PHP: What if I call a static method in non-static way

As Baba already pointed out, it results in an E_STRICT depending on your configuration.

But even if that's no problem for you, I think it's worth mentioning some of the pitfalls which may result from calling static methods in a non-static way.

If you have a class hierarchy like

class A {
public static function sayHello() {
echo "Hello from A!\n";
}

public function sayHelloNonStaticWithSelf() {
return self::sayHello();
}

public function sayHelloNonStaticWithStatic() {
return static::sayHello();
}
}

class B extends A {
public static function sayHello() {
echo "Hello from B!\n";
}

public function callHelloInMultipleDifferentWays() {
A::sayHello();
B::sayHello();
$this->sayHelloNonStaticWithSelf();
$this->sayHelloNonStaticWithStatic();
$this->sayHello();
}
}

$b = new B();
$b->callHelloInMultipleDifferentWays();

This produces the following output:

Hello from A!
// A::sayHello() - obvious

Hello from B!
// B::sayHello() - obvious

Hello from A!
// $this->sayHelloNonStaticWithSelf()
// self alweays refers to the class it is used in

Hello from B!
// $this->sayHelloNonStaticWithStatic()
// static always refers to the class it is called from at runtime

Hello from B!
// $this->sayHello() - obvious

As you can see, it's easy to achieve unexpected behaviour when mixing static and non-static method calls and techniques.

Therefore, my advice also is:
Use Class::method to explicitly call the static method you mean to call.
Or even better don't use static methods at all because they make your code untestable.

static method/function make call to non static function inside same class

Just go get some OOP terminology out of the way first: functions are static and methods are non-static (even though both are defined using the keyword function in PHP). Static class members belong to the class itself and so there is only one global instance of them. Non-static members belong to instances of the class and so each instance has its own copy of these non-static members1.

This means that you need an instance of the class -- called an object -- in order to use a non-static member.

In your case, startRun() does not appear to use any instance members of the object, so you could simply make it static to resolve the issue.

It's not clear in your case if you need to nest these functions inside of startRun() or if you should make them functions or methods of the class. There can be valid cases for nesting functions, but with the limited information in your question it's difficult to say if this is one such case.


1 You could make the argument that all instances share methods, and the object is simply passed to the method. Under the hood this is exactly what is going on, but on a conceptual level each instance has "its own methods." Think of instances sharing method implementations as an optimization.

Is it acceptable to mix static and non static methods in one class?

In this case you have to go with example 2, because what you're trying to do in example 1 will not work:

$food = new Food( "apple", "Nice juicy Pink Lady apple" );
Food::getAllFood(); //static

There will not be any food returned unless there's some hardcoded in the class. What you put in with the constructor, you put into the instance in $food. But you're calling the class itself Food::getAllFood() to retrieve. That doesn't make sense.

Are there cases where it would make sense to include a static method in a class? Yes. Like if I was making a db connection class that would hold a connection, but I also wanted to expose some date format methods that are related to the particular DBMS but don't actually require the connection to the db to be active. Anything touching the db would have to be non-static, but some transformation methods on data I've already pulled out could be static:

$db = new JDE_DBClass($connectionString);
$rows = $db->doSelectQuery("select * from whatever");
$date = JDE_DBClass::convertJDE_Date_to_PHP_Date($rows[0]['dateField']);

In this case you might want to do this to allow conversion without having to instantiate the db object, because perhaps you might need to convert back and forth between JDE's so-called Julian format and regular dates before even determining whether you need to connect to the db:

$date = JDE_DBClass::convertJDE_Date_to_PHP_Date('114309');

PHP static methods

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.



Related Topics



Leave a reply



Submit