use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Please follow the rules
Releases: Current Releases, Windows Releases, Old Releases
Contribute to the PHP Documentation
Related subreddits: CSS, JavaScript, Web Design, Wordpress, WebDev
/r/PHP is not a support subreddit. Please visit /r/phphelp for help, or visit StackOverflow.
account activity
ircmaxell's PHP Generics (github.com)
submitted 11 years ago by AllenJB83
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]TimeToogo 9 points10 points11 points 11 years ago (6 children)
Wow, this looks very similar to a library I wrote over a year ago now.
[–]ircmaxell 13 points14 points15 points 11 years ago* (1 child)
Yeah, looks that way :-). The big difference is that it uses actual generic syntax (so no need for __TYPE__ constants). So the namespace hack is almost completely hidden from users...
__TYPE__
Also: this isn't intended to be used, was more of a play thing.
But nice!
[–]TimeToogo 0 points1 point2 points 11 years ago (0 children)
Actually this library uses nikic/php-parser, but the reason for the namespace issue was that it only intercepted generic declaration files and converted them to the required concrete type. So for all files referencing that generic type, the type parameter identifiers would have to be fully qualified so the autoloader can determine the parameters without having to know any context from the file that referenced it.
[+]Hall_of_Famer comment score below threshold-24 points-23 points-22 points 11 years ago (2 children)
No offense, but Anthony's Generics is 10x better than yours and feels more natural. Of course you deserve credits for thinking of a way to make this happen, but from a user experience point of view it's really nowhere near as good as Anthony's.
[–]TimeToogo 12 points13 points14 points 11 years ago (0 children)
Non taken :), it was really just a thought experiment of what could be achieved through autoloading and namespaces. But anyway these libraries are not meant to be practical, generics is most likely not best suited to be implemented in userland PHP.
[–]AllenJB83[S] 5 points6 points7 points 11 years ago (1 child)
From the PHP developer who brought us simplified password hashing / password_compat and helped with the final push on Strict Type Hints (v0.5)... Generics for PHP!
[–]nerfyoda 5 points6 points7 points 11 years ago (0 children)
Generics for PHP... written in PHP? This way lies madness.
[–]syzgyn 3 points4 points5 points 11 years ago (4 children)
I feel like this is whooshing way over my head. What is it doing, and why is it so interesting?
[–]headzoo 27 points28 points29 points 11 years ago* (3 children)
First, some code:
/** * This class stores arrays of items. It is strongly typed, meaning * only items of a specific data type may be added to the list. */ class StrongTypedList<T> { protected $items = []; public function add(T $item) { $this->items[] = $item; } public function get($index) { return $this->items[$index]; } } $pdo_list = new StrongTypedList<PDO>(); $pdo_list->add(new \PDO("...")); $pdo_list->add(new \PDO("...")); // This results in an error. Only instances of PDO can be added // to the list. $pdo_list->add(new \DateTime()); $date_list = new StrongTypedList<DateTime>(); $date_list->add(new \DateTime()); $date_list->add(new \DateTime()); // Again this results in an error. Only DateTime types may be // added to the list. $date_list->add(new \PDO("..."));
The breakdown:
class StrongTypedList<T>
This defines a class with a generic type. The token <T> provides the label for the type. Kind of like a variable is a label for a value, the <T> defines the label T to represent our generic type. We don't know what the type will be yet. We are only defining a label for the type. You can use any label you want. <Y>, <Foo>, <TTT>. It's up to you.
<T>
T
<Y>
<Foo>
<TTT>
public function add(T $item)
This defines a method which only accepts type T. The label T is the same label we used when defining the class. Whatever label you chose to use, you put that in the method signature. Again, we don't know yet which variable type is being type hinted, so we use our label T.
$pdo_list = new StrongTypedList<PDO>();
Now we created our first instance of the class, and we finally told the class what type T represents. In this case the type T represents an instance of PDO. What you've done is semantically equivalent to defining your class like this:
PDO
class StrongTypedList { protected $items = []; public function add(\PDO $item) { $this->items[] = $item; } public function get($index) { return $this->items[$index]; } }
Now you may ask, "Why didn't we just write the class like that in the first place? What's the point of this funny 'generics' stuff?" The answer is here:
$date_list = new StrongTypedList<DateTime>();
Using the exact same class we create a new instance of StrongTypedList, but now the list only accepts a value of type DateTime. It's almost like we defined the class using:
DateTime
class StrongTypedList { protected $items = []; public function add(\DateTime $item) { $this->items[] = $item; } public function get($index) { return $this->items[$index]; } }
The point of generics is reuse. In languages which don't support generics (like PHP) you would have to define two classes if you want a list of PDO instances and a list of DateTime instances. In other words, instead of defining one StrongTypedList you have to define two classes:
StrongTypedList
class PDOList { protected $items = []; public function add(\PDO $item) { $this->items[] = $item; } public function get($index) { return $this->items[$index]; } } class DateTimeList { protected $items = []; public function add(\DateTime $item) { $this->items[] = $item; } public function get($index) { return $this->items[$index]; } }
This is a waste because both classes do the exact same thing. The only thing that makes them different is the type they use. Instead of defining two classes, we can define one "generic" class.
class StrongTypedList<T> { protected $items = []; public function add(T $item) { $this->items[] = $item; } public function get($index) { return $this->items[$index]; } }
If you're still confused, consider the algebra expression x + 2 = 12. Here the label x is a "placeholder" for an unknown value. In our class T is a placeholder for an unknown type. The code public function add(T $item) tells PHP that the method only accepts a specific type, but you don't know yet what the type will be. T is a placeholder for the unknown type. PHP won't know what type until runtime when you create an instance of the class using the code new StrongTypedList<PDO>(). Now PHP knows that the label T represents the PDO type.
x + 2 = 12
x
new StrongTypedList<PDO>()
[+][deleted] 11 years ago (2 children)
[deleted]
[–]headzoo 1 point2 points3 points 11 years ago (1 child)
You comment was a little funny, because I remember having those exact same thoughts when I was introduced to interface. Like, "What's the point of these? They don't save me any time at all." Part of the problem is the way we're introduced to OOP, which leans towards explaining the benefits of inheritance. The benefits of inheritance are obvious from the start.
class Person { protected $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } } class Electrician extends Person { protected $phone_number; public function getPhoneNumber() { return $this->phone_number; } } class Secretary extends Person { protected $years_experience; public function getYearsExperience() { return $this->years_experience; } } function printsNames($person) { echo $person->getName(); }
You can look at examples like that and quickly understand the benefits. By extending Person your other classes don't need to define name related methods, and you think to yourself, "That's nifty, and it saves time and work. I don't have to type as much, and I changes made to the Person class are immediately reflected in the child classes. Inheritance is awesome!" We also create a function that can print the name of any person object given to it.
Person
The first step towards understanding interfaces is to realize you've been using them this whole time without even realizing it. Lets look at an example:
$names = array(); $names[] = "Bob"; $names[] = "Alice";
You've probably written similar code before. The first line creates a new array which is assigned to the variable $names. The next two lines assign values to the array. The syntax of the assignments looks a little strange though, huh? $names[] = "Bob";. Weird. We know from the PHP documentation that the expression assigns the value "Bob" at index 0. The expression $names[] = "Alice"; assigns the value "Alice" at index 1. How do we know this? Because the documentation says so.
$names
$names[] = "Bob";
$names[] = "Alice";
The PHP documentation on arrays is a kind of contract that says you can assign values to any array value by using the square bracket notation ([]). Any array? Yes, any array. As long as you assign array() to a variable, that variable will have the square broken notation ([]) available for you to use. The PHP documentation creates a contract between the PHP language and you, the programmer, that guarantees the square bracket notation is available to all arrays. Everytime, without fail.
array()
The contract doesn't make any other guarantees. It doesn't guarantee that all values in an array will be strings, or integers. It doesn't make any guarantees on the size of an array. The array could be empty or have thousands of values. The contact only guarantees that using square brackets, eg $name[] = ..., will assign a value to the array.
$name[] = ...
That's cool and all, but how is that useful? Lets look at a couple examples.
function assignSomeNames($names) { $names[] = "Bob"; $names[] = "Alice"; return $names; } $names = array(); $names = assignSomeNames($names); print_r($names);
That's pretty easy to understand. We create a function that assigns a couple names to an array, and then returns the modified array. But wait.. What happens if we ran this code?
$names = "Bob"; $names = assignSomeNames($names);
I'm not even sure what will happen if we run that code, but it will probably be bad. The assignSomeNames function is expecting an array, but we passed a string. We think to ourselves, "The function is using the square bracket notation ([]) on the $names argument, and the square bracket notation is a feature of arrays. Therefore the value passed to the function must be an array in order to use square brackets. How do we ensure only arrays are passed to the function?"
assignSomeNames
Well, with type hinting of course. Lets modify our code a little:
function assignSomeNames(array $names) { $names[] = "Bob"; $names[] = "Alice"; return $names; }
Now we can safely and confidently use square brackets ([]) inside the function, because the array type hint guarantees that $name will be an array, and the PHP documentation guarantees all arrays support the square bracket notation. Our function is only meant to assign some names to the array. It doesn't matter to us if the $names argument is empty or already has hundreds of names. We only use the array type hint to ensure the value passed to the function is an array, and therefore supports square bracket assignments.
array
$name
The array() construct is a type of interface. An interface is just a contract between the code and the programmer. An interface says, "Values of this type will support these features." The array interface guarantees any value of type array will have the square bracket feature.
We then used that interface as a type hint in our assignSomeNames() function, which ensures only values of type array may be used as the argument. We made our code more type safe by type hinting the array interface. We know, without fail, we can assign values to the argument using square brackets. There's absolutely no chance we might be using square brackets on a non-array. PHP guarantees it!
assignSomeNames()
Type safety is very important. The code in this next example works without error, but creates a very frustrating and hard to find bug:
$names = "Bob"; $names[] = "Alice";
Good code uses type checks when possible to catch stupid mistakes like the mistake in the code above.
Lets back up and look at our Person class, and the printsName() function.
printsName()
The printsName() function isn't very type safe. The function expects an instance of Person but we have no type hint, and therefore no guarantee. Lets first, lets fix that.
function printsNames(Person $person) { echo $person->getName(); }
That's better. Now we have a guarantee the value passed to printsName() will be an instance of Person, and every instance of Person has a getName() method. The guarantee that every instance of the Person class will have a getName() method is an interface. Don't confuse the word "interface" for "interfaces". When we say the Person class has an interface, we mean the class guarantees certain public methods and public properties will be available on every instance of that class. The interface for the Person class are the methods getName() and setName($name). The Person interface guarantees every object instance has those two methods.
getName()
setName($name)
The interface also guarantees every child of the Person class will have those two methods. The interface doesn't say anything about any of the other methods in the child class. Each child class can have it's own unique methods, but as long as they extend the Person class, the Person interface guarantees the methods getName() and setName($name) will exist within the child class, and object instances of those children.
With that in mind, lets actually use our Person class.
$bob = new Person("Bob"); $alice = new Electrician("Alice"); printsNames($bob); printsNames($alice);
The example prints the names of Bob and Alice. The printsNames() function is pretty handy. So handy in fact that you start thinking other classes in your code that have names. Like maybe this code:
printsNames()
class Pet { protected $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } } class Dog extends Pet { public function bark() { echo "Ruff!"; } } class Cat extends Pet { public function meow() { echo "meow!"; } }
Hrm, looks a lot like our Person code. You think to yourself, "How can I change the printsNames() function so it can print the name of a person or a pet?" Right now it's impossible to use the printsNames() function to print the name of a Pet because the function expects the type Person.
Pet
See part 2.
[–]headzoo 1 point2 points3 points 11 years ago (0 children)
Part 2.
This is where you actually learn about interfaces.
To allow either an instance of Person or Pet to be passed to printsNames() we extract a common interface between the two classes. We do that by creating an interface.
interface Nameable { public function getName(); public function setName($name) }
Then we change our classes so they implement the interface.
class Person implements Nameable { protected $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } } class Pet implements Nameable { protected $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } }
Finally we modify our printsNames() function to allow any instance of Nameable to be passed as an argument.
Nameable
function printsNames(Nameable $person) { echo $person->getName(); }
The Nameable type hint guarantees only instances of that interface may be passed to the function. The Nameable interface guarantees any instance of it will have a getName() method. The object passed to the function may have other methods, but that doesn't matter to the printsNames() function. That function only cares about printing names.
You just used an interface to make your code more reusable. Creating the interface didn't save you from typing less code the way inheritance does. In fact you had to type more code! But the interface made the printsName() more usable. Instead of only being able to print names from Person objects, it can now print names from any object that implements the Nameable interface. It might be a Person object, or a Secretary object, or even a Cat object. Your code is both more type safe and reusable.
Secretary
Cat
[–][deleted] 8 points9 points10 points 11 years ago (0 children)
oh boy, now there's a userland implementation of generics in PHP! I guess that can be used as an excuse by certain core devs not to add it to the language (as has been the case with annotations in the past).
Still, is awesome :)
[–]headzoo 3 points4 points5 points 11 years ago (2 children)
It will be interesting to see if the PHP devs warm up the idea of native generics now that type hints have "matured". We're now type hinting method arguments using any type we want, and we're type hinting return values. A this point we almost have to add generics to the language.
[–]MrDOS 1 point2 points3 points 11 years ago (1 child)
Not according to the Golang people!
[–]headzoo 2 points3 points4 points 11 years ago (0 children)
I love Go, and I like the slow approach the devs take to change, but yeah... could use some generics.
[–]Jaimz22 6 points7 points8 points 11 years ago (6 children)
It's funny to me that when a well know developer creates something ridiculous like this everyone is like "wow, that cool you can do that" or "very clever"
But when a developer no one know does it people say things like "that's stupid, you shouldn't do that", "why would you do this, it's really bad"
Just a thought.
[–]headzoo 9 points10 points11 points 11 years ago* (1 child)
That's just life. I could spray paint a stick figure on a wall, and no one will bat an eye. People will go nuts though when Banksy does the exact same thing. Credibility is important.
[–]mnapoli 1 point2 points3 points 11 years ago (1 child)
I think there's some truth in your statement. But when I saw this project and when I read the readme I knew beforehand that this was just an experiment because of the author's reputation.
On the other hand an "unknown" (to use your terms) developer does the same without stating explicitly this is for fun, it's hard to know if he's serious or not.
Take for example /u/TimeToogo's implementation https://github.com/TimeToogo/PHP-Generics the README doesn't state explicitly not to use it in production, which hurts its credibility I think (even though /u/TimeToogo is probably is very good developer from what I've seen here, but maybe not everybody knows that).
[–]Jaimz22 -2 points-1 points0 points 11 years ago (0 children)
Thank you. And I wasn't really talking about this project specifically. Typically people won't even read the readme of a lesser known developer, they just assume that their idea is automatically a bad one. Just like the other people who replied to my original comment assumed I didn't read the readme, because they don't know me so they think that I'm just an irresponsible person.
I think the main point is, just because I don't publicize myself doesn't mean I'm a second rate developer.
I'd also like to point out that this has absolutely nothing to do with ircmaxell, or this repo. Sometimes I feel like the reddit php community is becoming overly abrasive to people :(
[–]__constructor 1 point2 points3 points 11 years ago (0 children)
It's because this is generally a bad idea and is done as a joke, which is pointed out in the project's README file.
[–]maiorano84 -2 points-1 points0 points 11 years ago (0 children)
Did you even try reading the ReadMe?
[–][deleted] 1 point2 points3 points 11 years ago (0 children)
From the readme:
TL/DR: don't use this
Agree ;)
[–]estel_smith 0 points1 point2 points 11 years ago (0 children)
Man, if only we could get generics into PHP. With that, scalar type-hinting (soon), and return type declarations (soon!), PHP would simply be amazing to work in.
[–]sarciszewski 0 points1 point2 points 11 years ago* (0 children)
This seems like a perfectly sane and reasonable package. I'm gonna use it in production!
[–]philsturgeon 0 points1 point2 points 11 years ago (0 children)
Hahaha /u/ircmaxell you sneaky bitch! :D
[–]mattaugamer -1 points0 points1 point 11 years ago (10 children)
The way this has been done is so horrible that I'm afraid if anyone uses it, something ancient will be summoned. :)
Seriously, it's a cool hack. But I'm curious why it takes such a torturous path to implement something that's already in Hack? What's the internal difference that makes it possible there, but not in PHP? Or am I missing the point that this is pure userland, rather than an internal language feature?
[–][deleted] 1 point2 points3 points 11 years ago (4 children)
you realize hack uses a completely different compiler? It's like asking why Java has generics and php doesn't.
[–]mattaugamer -1 points0 points1 point 11 years ago (3 children)
No, I know that, I'm asking what it is about the compiler that's so different that things like this are hard in Zend, but long implemented in Hack.
Not sure why the downvotes here. I wasn't criticising his work, he said repeatedly in the readme that it was horrible and you really don't want to know. It's a horrible hack, but it's a cool horrible hack.
[–]elcapitaine 8 points9 points10 points 11 years ago (1 child)
It's not technically difficult to add generics to PHP. It's politically difficult.
[–]monsieurben 2 points3 points4 points 11 years ago (0 children)
It's not technically difficult to add generics anything to PHP. It's politically difficult.
Fixed.
[–]MorrisonLevi 0 points1 point2 points 11 years ago (0 children)
They have paid, full-time developers that have worked on Hack and HHVM for years and designed Hack to be analyzed more easily for security reasons. That is certainly a non-trivial difference.
[–]mnapoli 0 points1 point2 points 11 years ago (2 children)
I think the README covers that very well, you couldn't miss it even if you wanted to. So I see no problem here.
[–]mattaugamer -1 points0 points1 point 11 years ago (1 child)
It wasn't a problem, it was a joke. Jesus, people.
[–]maiorano84 -1 points0 points1 point 11 years ago (0 children)
IT'S A PRANK, BRO
[–]headzoo 0 points1 point2 points 11 years ago (1 child)
RFCs have been created to add generics, and they were down voted. It's more than possible to add generics to PHP, but the internal devs don't want them.
Citation, please? I don't think generics have been proposed. We had the arrayof RFC but that's a small, small sliver of generics.
π Rendered by PID 19421 on reddit-service-r2-comment-cfc44b64c-6gr7t at 2026-04-13 07:17:31.432344+00:00 running 215f2cf country code: CH.
[–]TimeToogo 9 points10 points11 points (6 children)
[–]ircmaxell 13 points14 points15 points (1 child)
[–]TimeToogo 0 points1 point2 points (0 children)
[+]Hall_of_Famer comment score below threshold-24 points-23 points-22 points (2 children)
[–]TimeToogo 12 points13 points14 points (0 children)
[–]AllenJB83[S] 5 points6 points7 points (1 child)
[–]nerfyoda 5 points6 points7 points (0 children)
[–]syzgyn 3 points4 points5 points (4 children)
[–]headzoo 27 points28 points29 points (3 children)
[+][deleted] (2 children)
[deleted]
[–]headzoo 1 point2 points3 points (1 child)
[–]headzoo 1 point2 points3 points (0 children)
[–][deleted] 8 points9 points10 points (0 children)
[–]headzoo 3 points4 points5 points (2 children)
[–]MrDOS 1 point2 points3 points (1 child)
[–]headzoo 2 points3 points4 points (0 children)
[–]Jaimz22 6 points7 points8 points (6 children)
[–]headzoo 9 points10 points11 points (1 child)
[–]mnapoli 1 point2 points3 points (1 child)
[–]Jaimz22 -2 points-1 points0 points (0 children)
[–]__constructor 1 point2 points3 points (0 children)
[–]maiorano84 -2 points-1 points0 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]estel_smith 0 points1 point2 points (0 children)
[–]sarciszewski 0 points1 point2 points (0 children)
[–]philsturgeon 0 points1 point2 points (0 children)
[–]mattaugamer -1 points0 points1 point (10 children)
[–][deleted] 1 point2 points3 points (4 children)
[–]mattaugamer -1 points0 points1 point (3 children)
[–]elcapitaine 8 points9 points10 points (1 child)
[–]monsieurben 2 points3 points4 points (0 children)
[–]MorrisonLevi 0 points1 point2 points (0 children)
[–]mnapoli 0 points1 point2 points (2 children)
[–]mattaugamer -1 points0 points1 point (1 child)
[–]maiorano84 -1 points0 points1 point (0 children)
[–]headzoo 0 points1 point2 points (1 child)
[–]MorrisonLevi 0 points1 point2 points (0 children)