PHP 7 has introduced a new class feature called the anonymous class which will allow us to create objects without the need to name them. Anonymous classes can be nested. What are your thoughts on memory consumption, execution time, performance issues? Are there any metrics/stats available?
Anonymous classes are classes without programmer declared names, they are otherwise identical to normal classes.
Syntax allows them to be nested, just like functions:
function name() {
function sub() {
}
}
But just as the code above contains two globally accessible functions, the following code still contains two globally accessible classes:
class C {
function method () {
return new class{};
}
}
It gives you a kind of control over where the class is easily accessible from, in that sense they are nested.
They are not nested in the sense that an anonymous class declared inside another class is not able to access any members of the creating class.
So that this:
class C {
private $member;
public function method() {
return new class {
public function method() {
return $this->member;
}
};
}
}
Is not valid, because the anonymous class is not truly nested.
Related
What's the difference between creating a Global function in a Namespace (and calling it from the global namespace):
<?php
namespace MyNamespace {
function MyFunction($x, $y) {
return $x + $y;
}
}
namespace { //global code... in a new file
var_dump(MyNamespace\MyFunction(1,2));
}
and creating a static class method, and calling from the global Namespace?:
<?php
class MyClass {
public static function MyFunction($x, $y) {
return $x + $y;
}
}
var_dump(MyClass::MyFunction(1,2));
Is there any reason to prefer one method over the other?
Is there any reason to prefer one method over the other?
(below assumes you're asking/referring to a difference between a static class method and a function in a namespace)
Historically (before namespaces arrived), people were forced to use classes with static functions to not pollute a global namespace. This is one of the reasons you're likely to encounter this method more often.
You might prefer to use a static method if you need access to class's data or if you think of leaving a door to overriding them in descendant classes (the so-called 'flexibility and functionality' by some).
You might prefer a namespaced function when all you want is ...uh, ahem... a function. Think of some util, functional or collections functions like compose/partial, retry , filter/map/some/every etc. You are probably not expecting this to be overwritten in a child class, right? Neither it need access to some static class member.
There is one particular annoying problem with (namespaced) functions though, that classes don't suffer from. And it's autoloading. To put it short, there is no way to autoload a function at the moment. And this is another reason you'd likely encounter classes with static methods (when they don't necessarily need to be) more often in practice.
The primary difference is the global namespace can only ever have one function named MyFunction.
Using namespaces, each namespace can have it's own copy of MyFunction. This allows you to flexibility to create a common API without having to come up with clever names.
For example:
namespace Mail {
public static function send() {
// Send Mail
}
}
namespace SMS {
public static function send() {
// Send Text Message
}
}
That wouldn't be possible with a single global namespace. But now you have a predictable interface to call Mail\send() or SMS\send().
For classes, the ability to create these contracts works much better than functions within a namespace, because you get the ability to build interfaces and use abstraction.
For example:
abstract class Mail {
public static function send() {
// Create empty implementation (have to do this because it is static)
};
}
class MailChimp extends Mail {
public static function send() {
// Send Mail
}
}
class MailGun extends Mail {
public static function send() {
// Send Mail
}
}
With that, we can now namespace things under "Mail", but also effectively under the specific implementations of mail, and keep the common send() API we've come to know and love.
Is there any reason to prefer one method over the other?
Either will work. You just get more functionality and flexibility when dealing with classes.
Is there any chance there is an equivalent of Objective C Categories in PHP?
If all you want to do is break a huge class definition up over multiple files, and it's your class, then you can do that with traits. Just define some of the methods in a trait in a different file and use it in your class:
trait FooBar_ExtraMethods {
function foo () { return 'qux'; }
}
class FooBar {
use FooBar__ExtraMethods;
function bar () { return 'baz'; }
}
But if you want to add methods to somebody else's class, then there's simply no way to do that with vanilla PHP. Your choices are:
Live with the fact that this isn't possible and just write a function that takes instances of the class instead of extending it.
Use an extension to add the functionality into the language. Right now, the only contender is Dmitry Zenovich and Sara Golemon's Runkit. Zenovich's fork currently seems to be better-maintained and generally superior to Golemon's (although Golemon's is the one hosted on PECL), and the instructions below use Zenovich's fork.
Suppose I have an existing user-defined class Foo...
class Foo {
function methodA($arg) { return 2*$arg; }
}
I can add a method to it like this:
runkit_method_add('Foo', 'methodC', function ($arg) {
return 5 * $this->methodA($arg);
});
and call it like an ordinary method:
$f = new Foo;
echo $f->methodC(2); // 20
A couple of caveats:
You can't add methods to built-in classes. So if you want to use this to extend library-defined classes, you're good, but if you want to extend built-in classes like DateTime, you're out of luck.
This isn't remotely idiomatic - indeed, Runkit's tagline is "For all those things you.... probably shouldn't have been doing anyway.....". I leave it to your judgement whether to let that deter you from doing it.
It looks like a trait.
trait CarMaintenance{
public function needsOilChange(){}
public function changeOil(){}
public function rotateTires(){}
public function jumpBatteryUsingCar(){}
}
class Car {
use CarMaintenance;
public function startEngine() {}
public function drive() {}
public function turnLeft() {}
public function turnRight() {}
}
But traits could be reused in other class and could have their own hierarchy tree.
Assuming that I have to create a class that takes some text do some processing and return it ... with no dependency and it's a stateless class..
I'd like to know would be better to create a stateless class without constructor or just create a static class (in php it's just Static methods)
class like this:
class ClassName
{
public function processText($text)
{
// Some code
$text = $this->moreProcessing($text);
return $text;
}
protected function moreProcessing($text)
{
return $text;
}
}
and this:
class ClassName
{
public static function processText($text)
{
// Some code
$text = static::moreProcessing($text);
return $text;
}
protected static function moreProcessing($text)
{
return $text;
}
}
I Know that dependency injection into the class where these classes are used would be better but assume that I just won't have dependency injection..
My question is mainly would it be better to create static class for the simple example above?
Practically you will see no difference whatsoever.
It's only in the syntax, and the ability of a constructor to perform stuff automatically, though you still have to create instances to invoke the constructor, which in this case is not far off calling some equivalent static member function.
However, non-static member functions are supposed to affect internal state so, if you have no state, static member functions seem more conventional, and will be slightly less surprising to users of the class.
The best approach, though, is to stick your functions in a namespace. Classes are for data and functions operating on that data... even static ones.
I recently began to develop in php5 in an object oriented way and I'm stuck at something. I would really appreciate your help/recommendations.
Bear with me in this since it ended up in a mess :-(
This is my scenario (hope I can elaborate on this clearly): I have two dynamic classes, Client and Supplier which use methods of a static class called Vocabulary. Vocabulary is a class that pulls vocabulary terms from a source which can be: plain text file, mongodb database or mysql database. An entry in a configuration file determines which of the
aforementioned three types of sources the application will use.
class Client {
public function foo() {
...
Vocabulary::getTerm();
...
}
...
}
class Supplier {
public function bar() {
...
Vocabulary::getTerm();
...
}
...
}
class Vocabulary {
public static function useVocab($vocab) {
$_SESSION['vocab'] = $vocab;
}
public static function getTerm($termKey) {...}
...
}
I planned to create Vocabulary child classes for each of the types I want to support, for example: Vocabulary_file, Vocabulary_mongodb and Vocabulary_mysql.
Vocabulary_file will override its parent useVocab() because it needs to perform additional operations appart from setting the $_SESSION variable, but
Vocabulary_mongodb and Vocabulary_mysql don't need to override their useVocab() parent method (they just need the $_SESSION variable set).
All three Vocabulary "child" classes will override getTerm() method.
The following is what I tried and this is the mess I ended up with :-(
For Vocabulary_mongodb and Vocabulary_mysql, since useVocab() doesn't exist but is inherited from Vocabulary, "method_exists()" returns true and that call
causes an infinite loop.
I looks weird both calling the child explicitly in Vocabulary and calling the parent:: in the child class.
After lots of cups of coffee I have exhausted all my wits and my brain is damaged.
// Class Vocabulary modified to make it call the desired "child" class too
class Vocabulary {
// This would execute "child" class method
private static function _callChild($method, $args) {
$child_class = 'Vocabulary_' . Config::$vocab['type']; // Config::$vocab['type'] can be: file, mongodb or mysql
if (method_exists($child_class, $method)) {
return call_user_func_array($child_class . '::' . $method, $args);
} else {
return false;
}
}
public static function useVocab($vocab) {
$_SESSION['vocab'] = $vocab;
self::_callChild(__FUNCTION__, compact('vocab'));
}
public static function getTerm($termKey) {
$termKey = strtolower($termKey);
self::_callChild(__FUNCTION__, compact('termKey'));
}
...
}
class Vocabulary_file extends Vocabulary {
public static function useVocab($vocab) {
parent::useVocab($vocab);
// some specific stuff here
}
public static function getTerm($termKey) {
parent::getTerm($termKey);
// some specific stuff here
}
}
class Vocabulary_mongodb extends Vocabulary {
public static function getTerm($termKey) {
parent::getTerm($termKey);
// some specific stuff here
}
}
class Vocabulary_mysql extends Vocabulary {
public static function getTerm($termKey) {
parent::getTerm($termKey);
// some specific stuff here
}
}
I would like to know how can I design the Vocabulary classes in order to keep the Vocabulary::... like calls in Client and Supplier and let Vocabulary know which child class use for the type configured in "Config" class.
Any advice will be greatly appreciated.
Cheers
If you're using all static methods, you may as well not use OOP at all, it's basically all just global function calls. If you want inheritance with polymorphism to work, you pretty much need to instantiate your classes. The polymorphism then comes from the fact that the instantiated objects can be anything, but you're calling the same methods on them. E.g.:
abstract class Vocabulary {
abstract public function getTerm($termKey);
}
class Vocabulary_File extends Vocabulary {
public function getTerm($termKey) {
// get from file
}
}
class Vocabulary_MySQL extends Vocabulary {
public function getTerm($termKey) {
// get from database
}
}
You can use this polymorphic like this:
if (mt_rand(0, 1)) {
$vocab = new Vocabulary_File;
} else {
$vocab = new Vocabulary_MySQL;
}
// This call is polymorphic.
// What exactly it does depends on which class was instantiated.
$vocab->getTerm('foo');
This is how polymorphism is really useful. The interface (getTerm($termKey)) is defined and unchanging between classes, but the specific implementation changes. If your code is hardcoding calls to Vocabulary::getTerm(), that's not polymorphism. With your structure you're also violating an important OO design rule: The parent does not know about its children, and it does not interact with its children. The children override functionality of the parent, not the other way around.
You also shouldn't use the $_SESSION as a form of global storage. Keep objects self contained.
The keyword self suffers from inability to handle 'late-static-binding'. Basically, in the parent class, self thinks it's the parent class when it's inside it's own static functions (since self is still evaluated at compile time for legacy reasons).
You need to use static instead of self in the parent class (assuming you have php 5.3 or higher).
BTW: the parent keyword functions as you'd expect as the parent has to be known at compile time anyhow.
Here's an example:
public static function getTerm($termKey) {
$termKey = strtolower($termKey);
static::_callChild(__FUNCTION__, compact('termKey'));
}
If you're using php 5.2 and earlier, you have to try a hack around, like require all child classes to have static functions that return their class name. I hope you're on php 5.3 or higher...
Why in PHP you can access static method via instance of some class but not only via type name?
UPDATE: I'm .net developer but i work with php developers too. Recently i've found this moment about static methods called from instance and can't understand why it can be usefull.
EXAMPLE:
class Foo
{
public static Bar()
{
}
}
We can accept method like this:
var $foo = new Foo();
$foo.Bar(); // ??????
In PHP
the class is instantiated using the new keyword for example;
$MyClass = new MyClass();
and the static method or properties can be accessed by using either scope resolution operator or object reference operator. For example, if the class MyClass contains the static method Foo() then you can access it by either way.
$MyClass->Foo();
Or
MyClass::Foo()
The only rule is that static methods or properties are out of object context. For example, you cannot use $this inside of a static method.
Class Do {
static public function test() {
return 0;
}
}
use like this :
echo Do::test();
Why in PHP you can access static method via instance of some class but not only via type name?
Unlike what you are probably used to with .NET, PHP has dynamic types. Consider:
class Foo
{
static public function staticMethod() { }
}
class Bar
{
static public function staticMethod() { }
}
function doSomething($obj)
{
// What type is $obj? We don't care.
$obj->staticMethod();
}
doSomething(new Foo());
doSomething(new Bar());
So by allowing access to static methods via the object instance, you can more easily call a static function of the same name across different types.
Now I don't know if there is a good reason why accessing the static method via -> is allowed. PHP (5.3?) also supports:
$obj::staticMethod();
which is perhaps less confusing. When using ::, it must be a static function to avoid warnings (unlike ->, which permits either).
In PHP, while you're allowed to access the static method by referencing an instance of the class, you don't necessarily need to do so.
For example, here is a class with a static function:
class MyClass{
public static function MyFunction($param){
$mynumber=param*2;
return $mynumber;
}
You can access the static method just by the type name like this, but in this case you have to use the double colon (::), instead of "->".
$result= MyClass::MyFunction(2);
(Please note you can also access the static method via an instance of the class as well using "-->"). For more information: http://php.net/manual/en/language.oop5.static.php
In PHP 7 it seems to be absolutely necessary for you to be able to do $this->staticFunction(). Because, if this code is written within an abstract class and staticFunction() is also abstract in your abstract class, $this-> and self:: deliver different results!
When executing $this->staticFunction() from a (non-abstract) child of the abstract class, you end up in child::staticFunction(). All is well.
However, executing self::staticFunction() from a (non-abstract) child of the abstract class, you end up in parent::staticFunction(), which is abstract, and thusly throws an exception.
I guess this is just another example of badly designed PHP.
Or myself needing more coffee...