# [RFC] Static classes (Was Abstract final classes)

- Thread: https://externals.io/message/79338
- Original archive: https://news-web.php.net/php.internals/79338
- Started by Robert Stoll on 2014-12-01T13:58:58+00:00
- Messages: 20
- RFC: Static class (Declined) — https://externals.io/rfc/static_class.md
- RFC: Abstract final classes / Static classes (Declined) — https://externals.io/rfc/abstract_final_class.md
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #79338 — Robert Stoll — 2014-12-01T13:58:58+00:00

URL: https://externals.io/message/79338#79338

Hi Guilherme,

I read your updated RFC:
https://wiki.php.net/rfc/abstract_final_class

IMO the RFC as such makes sense now (abstract final confusion is eliminated. In addition to turn methods implicitly into static methods, the __construct of a static class should be implicitly private as well.
I am not sure what makes more sense for PHP, but just as thought-provoking impulse, wouldn't it be better just to check that all methods are static and __construct private instead of turning methods magically into static methods and __construct private?

And then there is one bit which I do not understand. What do you mean with:
"There's no way of adding static variables to a namespace. This would address this issue too."

How does this RFC address this problem? 

Cheers,
Robert

---

## #79339 — Andrea Faulds — 2014-12-01T14:32:41+00:00

URL: https://externals.io/message/79338#79339 · In reply to: #79338

Hi all!

> 
> 
> I read your updated RFC:
> https://wiki.php.net/rfc/abstract_final_class

Hmm, I don’t like this new RFC either. Static classes in languages like C# exist because the language designers made the dogmatic decision to require everything to be a class. Thus, to make collections of functions, your only choice is to make a “utility class" with a bunch of static methods. To make this easier, the `static` keyword was added to make this easier in C# - Java doesn’t have this keyword, but it has the same pattern of static method-only classes. But PHP is not one of these dogmatic “everything must be a class” languages: it has true global functions which can be namespaced.

So, why, then, does PHP need static classes? As I see it, there are two reasons:

  (1) Functions currently cannot be autoloaded
  
  (2) Encapsulation of state (private/protected static properties)

I think both of these can be solved without perpetuating what I feel is an anti-pattern, the “utility class”. If they are solved, the need for utility classes goes away.

To implement (1), someone just needs to go and finally implement function autoloading. I think Joe Watkins (krakjoe) might’ve said he’d write a patch for that, but I may be wrong. I’d certainly like to help with this effort.

Implementing (2) is more difficult. We currently don’t have file-local variables like C has, we don’t even have namespaced variables. We do have static variables within functions, however. I can think of a few possible approaches to this:

  (1) Say that global state is evil and refuse to implement it. Some people (myself included, to an extent) would argue that global state is “spooky action at a distance” and we shouldn’t be encouraging it. In this case we encourage users to simply make normal, non-static/abstract classes and to pass an instance around. This is generally good programming practise anyway.

  (2) Add lexically-scoped variables, and allow normal global functions to be closures. By this I mean we add something like JavaScript’s `let` keyword that would make a variable that is unset when it falls out of scope (end of a {} block, end of a file etc.). Then, we allow normal functions to use the `use ($var)` syntax and close over variables. That’d look something like this:

        <?php
        let $x = 0;
        function getCounter() use(&$x) {
            return $x;
        }
        function incrementCounter() use(&$x) {
            return $x++;
        }
        // since this is the end of the file, $x falls out of scope

      I’d quite like this, as the introduction of lexically-scoped variables would have other advantages, too. They would make foreach() by-reference much less error-prone, for example:

        <?php
        foreach ($array as let &$item) {
             // do stuff with $item
        }
        // $item is unset here, since it fell out of scope when we left the {} block

  (3) Add file-local variables using the `static` keyword (à la C). That’d work something like this:

        <?php
        static $x = 0;
        function getCounter() {
              global $x;
              return $x;
        }
        // etc.

      This would work similarly to `let`, I suppose, it’d just only be useful for files.

  (4) Add namespace-local variables. No idea quite how this’d work.

I’m not sure which of these is the best, though I’d leans towards (1) or (2). But I definitely feel that adding a `static` modifier for classes is solving the wrong problem. We don’t need to make utility classes easier to create. Rather, we need to solve the long-standing problems which force people to create utility classes in the first place.

Thanks!
--
Andrea Faulds
http://ajf.me/

---

## #79341 — guilhermeblanco@gmail.com — 2014-12-01T15:27:46+00:00

URL: https://externals.io/message/79338#79341 · In reply to: #79339

Hi Andrea,

Thanks a lot for putting efforts thinking through this problem.
Indeed we have 3 problems that leads to "static classes". You detailed 2 of
them.
The third is around encapsulation. I may want functions that are reused by
other functions at the namespace level, but that shouldn't be used outside
of it. By purely supporting (1), you still didn't address this issue. That
would be easily addressed by having private static functions inside of the
static class.
So, let me recap the 3 motivations:

(1) Function/Namespaced function autoloading
(2) State encapsulation
(3) Function scoping

Heading back to your drill down in (2), I feel that we're adding more
complexity to something that can and it is at some extent be easily
supported through classes.
I actually thought about having "let" originally and using as "global", but
I gave up on the idea due to patch's complexity and also because it didn't
matter how far I was thinking through this, something was popping up my
head telling it was wrong. I decided to share my idea with a friend which
pointed me to HHVM's support and then I decided to work on that original
patch.
So, as you walk through your options, didn't it feel wrong to you? Static
classes are an easy addiction to the language and would have a negligent
performance impact, since it just adds 2 conditions in zend_vm and zend_api.

Again, I wouldn't necessarily use this concept I'm proposing right out the
bet, but I do see there are use cases.
I plan to redo my patch and get back for review once I finalize.

Cheers,



> Hi all!
>
> > […]
>
> Hmm, I don’t like this new RFC either. Static classes in languages like C#
> exist because the language designers made the dogmatic decision to require
> everything to be a class. Thus, to make collections of functions, your only
> choice is to make a “utility class" with a bunch of static methods. To make
> this easier, the `static` keyword was added to make this easier in C# -
> Java doesn’t have this keyword, but it has the same pattern of static
> method-only classes. But PHP is not one of these dogmatic “everything must
> be a class” languages: it has true global functions which can be namespaced.
>
> So, why, then, does PHP need static classes? As I see it, there are two
> reasons:
>
>   (1) Functions currently cannot be autoloaded
>
>   (2) Encapsulation of state (private/protected static properties)
>
> I think both of these can be solved without perpetuating what I feel is an
> anti-pattern, the “utility class”. If they are solved, the need for utility
> classes goes away.
>
> To implement (1), someone just needs to go and finally implement function
> autoloading. I think Joe Watkins (krakjoe) might’ve said he’d write a patch
> for that, but I may be wrong. I’d certainly like to help with this effort.
>
> Implementing (2) is more difficult. We currently don’t have file-local
> variables like C has, we don’t even have namespaced variables. We do have
> static variables within functions, however. I can think of a few possible
> approaches to this:
>
>   (1) Say that global state is evil and refuse to implement it. Some
> people (myself included, to an extent) would argue that global state is
> “spooky action at a distance” and we shouldn’t be encouraging it. In this
> case we encourage users to simply make normal, non-static/abstract classes
> and to pass an instance around. This is generally good programming practise
> anyway.
>
>   (2) Add lexically-scoped variables, and allow normal global functions to
> be closures. By this I mean we add something like JavaScript’s `let`
> keyword that would make a variable that is unset when it falls out of scope
> (end of a {} block, end of a file etc.). Then, we allow normal functions to
> use the `use ($var)` syntax and close over variables. That’d look something
> like this:
>
>         <?php
>         let $x = 0;
>         function getCounter() use(&$x) {
>             return $x;
>         }
>         function incrementCounter() use(&$x) {
>             return $x++;
>         }
>         // since this is the end of the file, $x falls out of scope
>
>       I’d quite like this, as the introduction of lexically-scoped
> variables would have other advantages, too. They would make foreach()
> by-reference much less error-prone, for example:
>
>         <?php
>         foreach ($array as let &$item) {
>              // do stuff with $item
>         }
>         // $item is unset here, since it fell out of scope when we left
> the {} block
>
>   (3) Add file-local variables using the `static` keyword (à la C). That’d
> work something like this:
>
>         <?php
>         static $x = 0;
>         function getCounter() {
>               global $x;
>               return $x;
>         }
>         // etc.
>
>       This would work similarly to `let`, I suppose, it’d just only be
> useful for files.
>
>   (4) Add namespace-local variables. No idea quite how this’d work.
>
> I’m not sure which of these is the best, though I’d leans towards (1) or
> (2). But I definitely feel that adding a `static` modifier for classes is
> solving the wrong problem. We don’t need to make utility classes easier to
> create. Rather, we need to solve the long-standing problems which force
> people to create utility classes in the first place.
>
> Thanks!
> --
> Andrea Faulds
> http://ajf.me/
>
>
>
>
>


-- 
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada

---

## #79342 — Andrea Faulds — 2014-12-01T15:32:53+00:00

URL: https://externals.io/message/79338#79342 · In reply to: #79341

Hi!

> 
> 
> Hi Andrea,
> 
> Thanks a lot for putting efforts thinking through this problem.
> Indeed we have 3 problems that leads to "static classes". You detailed 2 of them.
> The third is around encapsulation. I may want functions that are reused by other functions at the namespace level, but that shouldn't be used outside of it. By purely supporting (1), you still didn't address this issue. That would be easily addressed by having private static functions inside of the static class.

Hmm. Well, having functions not to be used outside of the namespace/file isn’t a problem unique to classes. That would be useful for people writing normal functions. Having something like static functions would be great.

> So, as you walk through your options, didn't it feel wrong to you? Static classes are an easy addiction to the language and would have a negligent performance impact, since it just adds 2 conditions in zend_vm and zend_api.

Yes, they’re a simple addition, but I still think they’re the wrong solution to the problem. We shouldn’t force people to use classes for simple collections of functions. People have wanted function autoloading for years. I say it’s high time we add that.

Thanks!
--
Andrea Faulds
http://ajf.me/

---

## #79343 — Christoph Becker — 2014-12-01T16:12:51+00:00

URL: https://externals.io/message/79338#79343 · In reply to: #79342

Andrea Faulds wrote:

> Yes, they’re a simple addition, but I still think they’re the wrong
> solution to the problem. We shouldn’t force people to use classes for
> simple collections of functions. People have wanted function
> autoloading for years. I say it’s high time we add that.

Maybe <https://wiki.php.net/rfc/function_autoloading> should be reopened?

-- 
Christoph M. Becker

---

## #79344 — Andrea Faulds — 2014-12-01T16:14:22+00:00

URL: https://externals.io/message/79338#79344 · In reply to: #79343

> 
> 
> Andrea Faulds wrote:
> 
> > […]
> 
> Maybe <https://wiki.php.net/rfc/function_autoloading> should be reopened?

Perhaps. I did want to revive that RFC, but I disliked Anthony’s approach to implementing it (new set of functions, namespaced) and the patch wasn’t for phpng. 
--
Andrea Faulds
http://ajf.me/

---

## #79345 — Rowan Collins — 2014-12-01T16:36:46+00:00

URL: https://externals.io/message/79338#79345 · In reply to: #79341

guilhermeblanco@gmail.com wrote on 01/12/2014 15:27:
> (1) Function/Namespaced function autoloading
> (2) State encapsulation
> (3) Function scoping

I would add (4) static polymorphism, which Late Static Binding 
explicitly supports.

> But PHP is not one of these dogmatic “everything must be a class” languages: it has true global functions which can be namespaced.

By the same token, PHP is not one of those dogmatic languages which says 
that every class must have at least one instance. There may be 
advantages to giving your Factory class a constructor, but there is 
nothing in the language itself to stop you making it entirely out of 
static methods, and even sub-classing it from an abstract base using LSB.

The only thing missing is a standardised, enforced, annotation on the 
class to declare that you are using this ability and instances will 
never be created.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #79351 — Stanislav Malyshev — 2014-12-01T17:46:15+00:00

URL: https://externals.io/message/79338#79351 · In reply to: #79339

Hi!

> (2) Add lexically-scoped variables, and allow normal global functions
> to be closures. By this I mean we add something like JavaScript’s
> `let` keyword that would make a variable that is unset when it falls
> out of scope (end of a {} block, end of a file etc.). Then, we allow
> normal functions to use the `use ($var)` syntax and close over
> variables. That’d look something like this:
> 
>         <?php
>         let $x = 0;
>         function getCounter() use(&$x) {
>             return $x;
>         }
>         function incrementCounter() use(&$x) {
>             return $x++;
>         }
>         // since this is the end of the file, $x falls out of scope
> 

This looks like you're trying to create a class without calling it a
class. Now, I agree that not everything should be a class. But what
you're doing - set of functions linked by common behavior and sharing a
common state - is a perfect fit for something classes and objects are
used in PHP. So why not just use them instead of inventing creative ways
of doing the same but in more complicated way?

Moreover, since your example is clearly not a singleton - it is hard to
imagine any program that would have use for just one counter but never
any more - it is a classic example of something that should be an
object. It might be a wrong example, but I have hard time seeing any
example of something that has a group of functions, bound by common
functionality, has a shared state and still should not and can not be
expressed as a class/object. That's literally what they are made for.

Now, utility classes do suck, but they suck not because they do what you
described - on the contrary, they suck exactly because they are usually
a bag of random, unrelated functions bound by nothing but the common
trait of "we don't have other places to put them in". But for that,
plain old functions work just fine in PHP.
-- 
Stas Malyshev
smalyshev@gmail.com

---

## #79346 — Levi Morrison — 2014-12-01T17:58:29+00:00

URL: https://externals.io/message/79338#79346 · In reply to: #79345

> The only thing missing is a standardised, enforced, annotation on the class
> to declare that you are using this ability and instances will never be
> created.

Let's say a class has no members: what's the harm in instantiating it?
Sure, it logically doesn't do anything useful, but is this user error
such a big deal that we alter the language to disallow it?

---

## #79347 — Patrick Schaaf — 2014-12-01T18:15:41+00:00

URL: https://externals.io/message/79338#79347 · In reply to: #79345

Am 01.12.2014 17:37 schrieb "Rowan Collins" <rowan.collins@gmail.com>:
>
> guilhermeblanco@gmail.com wrote on 01/12/2014 15:27:
>
> > […]

> I would add (4) static polymorphism, which Late Static Binding explicitly
supports.

Amen!

In several places in our codebase, I make use of per-request constants by
having an autoloaded baseclass file which uses class_alias for
specialization, like this:

// in some/class.inc
class some_class__base {
   ... common methods and default implementation
}
if (class_exists('some_class_'.SOME_CONSTANT)) {
     class_alias('some_class', 'some_class_'.SOME_CONSTANT);
} else {
     class_alias('some_class', 'some_class__base');
}

// in some/class/special.inc
class some_class_special extends some_class_base {
   .... specialization ...
}

Calling code simply uses some_class::foo() without caring whether the
concrete script run then uses the specialized class, or the base class.

> The only thing missing is a standardised, enforced, annotation on the
class to declare that you are using this ability and instances will never
be created.

I that regard, I'm quite happy with private function __construct, where
desired.

best regards
  Patrick

---

## #79349 — Rowan Collins — 2014-12-01T18:54:14+00:00

URL: https://externals.io/message/79338#79349 · In reply to: #79346

Levi Morrison wrote on 01/12/2014 17:58:
> > […]
> Let's say a class has no members: what's the harm in instantiating it?
> Sure, it logically doesn't do anything useful, but is this user error
> such a big deal that we alter the language to disallow it?

The same could be said of many function and class modifiers - they exist 
as self-documenting, mostly compile-time, assertions. There may not be a 
compelling reason to add one, but "the user's self-discipline should be 
good enough" isn't a very compelling reason not to.

I do think the keyword should trigger simple enforcement, though, not 
automagically change the behaviour.

static class Foo {
     function bar() {
         echo do_something_with($this);
     }
}

Much nicer (and just as easy) for that to give a compile-time error of 
"Static class Foo cannot contain non-static function bar" than for it to 
autoload fine, and then give a less obvious error when Foo::bar() is run 
(probably to do with a non-existent variable, since $this is always 
undefined inside a static function).

Programmers, and automated tools, won't know about the "static class" 
annotation immediately, but hopefully already know what "static 
function" means.

Note that this is the same as with "abstract function" vs "abstract 
class", only the other way around - adding an abstract function doesn't 
implicitly convert a class to be abstract, it refuses to compile if you 
don't explicitly do so.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #79352 — Lars Strojny — 2014-12-01T19:44:35+00:00

URL: https://externals.io/message/79338#79352 · In reply to: #79338

Hi Guilherme, hi Robert.

> 
> 
> I am not sure what makes more sense for PHP, but just as thought-provoking impulse, wouldn't it be better just to check that all methods are static and __construct private instead of turning methods magically into static methods and __construct private?

I very much like the RFC in its current state except for the implicit static. While we can preserve the behaviour of automatically turning methods into static methods, this should indeed trigger a warning.

cu,
Lars

---

## #79353 — guilhermeblanco@gmail.com — 2014-12-01T19:46:28+00:00

URL: https://externals.io/message/79338#79353 · In reply to: #79352

I'm working on a patch right now and I removed the implicit configuration
of static to methods.
It's only missing reflection magic. Should be out of the oven in one hour
or less.



> Hi Guilherme, hi Robert.
>
> > […]
> thought-provoking impulse, wouldn't it be better just to check that all
> methods are static and __construct private instead of turning methods
> magically into static methods and __construct private?
>
> I very much like the RFC in its current state except for the implicit
> static. While we can preserve the behaviour of automatically turning
> methods into static methods, this should indeed trigger a warning.
>
> cu,
> Lars




-- 
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada

---

## #79355 — Stanislav Malyshev — 2014-12-01T20:17:48+00:00

URL: https://externals.io/message/79338#79355 · In reply to: #79349

Hi!

> static class Foo {
>     function bar() {
>         echo do_something_with($this);
>     }
> }
> 
> Much nicer (and just as easy) for that to give a compile-time error of
> "Static class Foo cannot contain non-static function bar" than for it to
> autoload fine, and then give a less obvious error when Foo::bar() is run
> (probably to do with a non-existent variable, since $this is always
> undefined inside a static function).

This example is fit the narrow purpose of being the example, but you
could have as easily written "static function bar" and be back to square
one. I'm not sure how language-enforced "all methods must be static" is
really useful - if you don't want to instantiate it, put a private ctor
or make it abstract. If you want static methods, just make them static.
It won't help you anyway if you use $this in static methods.
-- 
Stas Malyshev
smalyshev@gmail.com

---

## #79356 — Andrea Faulds — 2014-12-01T20:30:46+00:00

URL: https://externals.io/message/79338#79356 · In reply to: #79351

> 
> 
> Hi!
> 
> > […]


> Moreover, since your example is clearly not a singleton - it is hard to
> imagine any program that would have use for just one counter but never
> any more - it is a classic example of something that should be an
> object.

That was just a frivolous example to show how the syntax works, it’s not a sensible example of why you’d want this functionality.

> This looks like you're trying to create a class without calling it a
> class. Now, I agree that not everything should be a class. But what
> you're doing - set of functions linked by common behavior and sharing a
> common state - is a perfect fit for something classes and objects are
> used in PHP. So why not just use them instead of inventing creative ways
> of doing the same but in more complicated way?

> It might be a wrong example, but I have hard time seeing any
> example of something that has a group of functions, bound by common
> functionality, has a shared state and still should not and can not be
> expressed as a class/object. That's literally what they are made for.

> Now, utility classes do suck, but they suck not because they do what you
> described - on the contrary, they suck exactly because they are usually
> a bag of random, unrelated functions bound by nothing but the common
> trait of "we don't have other places to put them in". But for that,
> plain old functions work just fine in PHP.

Yeah, I see your point. For encapsulated state with associated functions to work with that state, a class is the way to go. For miscellaneous functions with no shared state, they should just be functions, not in a class.

However, I still don’t think `static` is a good idea. Adding function autoloading eliminates one use case - a bag of random, unrelated functions. But it leaves the other: a set of functions to operate on global state. The problem is that, well, global state is rarely a good thing, I don’t think we should be encouraging it. If people really want to make a singleton or a final class with a private constructor, be my guest, but I don’t think we should make it any easier for them.

--
Andrea Faulds
http://ajf.me/

---

## #79359 — Rowan Collins — 2014-12-01T21:56:24+00:00

URL: https://externals.io/message/79338#79359 · In reply to: #79356

> 
> The problem is that, well, global state is rarely a good thing, I don’t think we should be encouraging it.

To get a bit philosophical: Is it really the language's job to make that decision? Is there a difference between "encouraging", "allowing", and "enabling"?

Purely static classes are a reality whether this feature is added or not. They do things namespaces can't (and probably shouldn't), but are simpler to work with than singletons (which they closely resemble) or full-blown Dependency Injection. Declaring a static class is just a way of acknowledging that this is a deliberate decision, and instance members should not be added.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #79361 — guilhermeblanco@gmail.com — 2014-12-01T22:33:15+00:00

URL: https://externals.io/message/79338#79361 · In reply to: #79359

PR with this feature request: https://github.com/php/php-src/pull/929

On Mon, Dec 1, 2014 at 4:56 PM, Rowan Collins <rowan.collins@gmail.com>
wrote:

> 
> > […]
> think we should be encouraging it.
>
> To get a bit philosophical: Is it really the language's job to make that
> decision? Is there a difference between "encouraging", "allowing", and
> "enabling"?
>
> Purely static classes are a reality whether this feature is added or not.
> They do things namespaces can't (and probably shouldn't), but are simpler
> to work with than singletons (which they closely resemble) or full-blown
> Dependency Injection. Declaring a static class is just a way of
> acknowledging that this is a deliberate decision, and instance members
> should not be added.
>
> Regards,
> --
> Rowan Collins
> [IMSoP]
>
>
> --
> 
> 
>
>


-- 
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada

---

## #79362 — Levi Morrison — 2014-12-01T22:41:53+00:00

URL: https://externals.io/message/79338#79362 · In reply to: #79359

Perhaps I have missed it in the noise, but have any other mainstream
languages (or new hipster ones; I don't care) have something
equivalent to the proposed static classes?

---

## #79363 — guilhermeblanco@gmail.com — 2014-12-01T22:43:11+00:00

URL: https://externals.io/message/79338#79363 · In reply to: #79362

Yes, C# documented here:
http://msdn.microsoft.com/en-us/library/79b3xss3.aspx



> Perhaps I have missed it in the noise, but have any other mainstream
> languages (or new hipster ones; I don't care) have something
> equivalent to the proposed static classes?
>
> --
> 
> 
>
>


-- 
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada

---

## #79364 — Stanislav Malyshev — 2014-12-01T23:22:03+00:00

URL: https://externals.io/message/79338#79364 · In reply to: #79359

Hi!

> To get a bit philosophical: Is it really the language's job to make
> that decision? Is there a difference between "encouraging",
> "allowing", and "enabling"?

I think, yes on both. The PHP tradition is to allow doing stuff that may
look weird (most languages won't allow you to do $$foo) but still there
are practices that we encourage, especially in OO space, and some even
that we enforce quite strictly (such as inheritance rules for methods).

> Purely static classes are a reality whether this feature is added or
> not. They do things namespaces can't (and probably shouldn't), but

Of course, you can create class containing of only static members. The
question is whether we need a language construct for ensuring that
certain class has only static members. I'm not sure this requires a
language-level construct.
-- 
Stas Malyshev
smalyshev@gmail.com
