PHP interesting creation of the class instance - php

I've read about this interesting syntax in PHP:
$value = (new MyClass)->attribute1;
Is it ok to use it? I've never seen anything like this in any code I've analyzed. Any pros and cons?
Why can't I set the attribute using this syntax? Structures like this:
(new MyClass)->attribute1 = 'value1';
throw errors at '=' sign, no matter if the attribute exists in the class already.

Well i don't see the point of using it since you loose your reference to the object, you cannot use it anymore, and it breaks the OO concept.
I think (new MyClass)->attribute1 is resolved first, so it is the same as writing something like 42 = 12

This may have a sense, if the class MyClass supports internal static list (or hashmap) of all existing instances. This way you can create new object and get its unique ID or index in the list for future references (for example, by sending it via cookies to a client).
As for assignment, you'd post exact error message for this case. I can guess, that the error is about assigning something to a temporary value which is about to be destroyed.

Related

when to use '#' before in a super global variable in object oriented php? [duplicate]

This question already has answers here:
What is the use of the # symbol in PHP?
(11 answers)
Closed 6 years ago.
Inside a function I want to return a super global variable. It shows undefined. but when i use '#' before this super global variable then it is done. i want to know the actual use of '#'.
below is my code
public function getSession(){
return $_SESSION['login'];
}
There are some good use cases for using # in PHP.
One great example is if you're writing object oriented code and you want a clean object api that throws exceptions when something goes wrong. You're designing your class, and your object performs, say, a file_get_contents call in there. In order to maintain a nice, self-contained object api, you'll want to throw an exception when something goes wrong.
#file_get_contents(...)
Prefixing the # there allows you suppress the warning and ensure that the user of this object gets an exception. Instead, check for a false then throw your exception.
Why do you have to do this? Because php is a daft mix of functions that have no similarities or standards when compared with each other.
And with your specific example, which is nothing to do with #, you'd do an isset($_SESSION['login']).
You are looking at this the wrong way.
You should never access PHP superglobals from within the class to begin with. Instead you should use them as parameters, when creating the instance at the bootstrap stage of your code:
$request = new Request(
$_POST,
$_GET, new Session($_SESSION)
);
Kinda like this.
Then this $request instance is passes to the class, which is handling your user input. This has two major benefits:
ability to control and alter the perceived user input at runtime with affecting global scope (in cases when you are working in a legacy codebase, where parts of it are still based on include-oriented programming)
ability to test your code independently from the webserver
This boils down to:
"When is it okay to use #?"
And the answer is: virtually never.
The # operator suppresses errors, that's the only thing it does. There's basically no sane situation in which you'd ever want to suppress errors. Because error reports help you see, well, errors, mistakes, typos, wrong assumptions in your code. In this case your code is making the assumption that $_SESSION['login'] always exists. That assumption is apparently wrong, and PHP tells you about it with a notice. Either you have a bug in your code that causes this assumption to fail, or you need to change the assumption by using isset($_SESSION['login']).
The only legitimate case for using # is if you're working with 3rd party code where you expect errors and know what they mean and know they are harmless and which cannot be suppressed any other way.
First of all there is no need to return a super gloab just because its super global somethign like this
public function Foo(){
$_SESSION['login'] .= $_SESSIN['login'] . " blah blah";
}
its fine.
The # is using for turning off notices. And thats why whe you use assume its working because you had just turn off the notice :). The $_SESSION is still undefined . Take a look at http://php.net/manual/en/language.operators.errorcontrol.php

When to use :: and when to use # in documentation

I've seen both used in documentation of a PHP library (seemingly interchangeably) and was wondering if there's a method to the madness and a time when each should be used? (Or if they mean something different, a nuance which I've therefore missed in the documentation)
Examples:
ClassName#foo() // a method
ClassName::bar() // a method
ClassName::baz // a property
I've not (yet) seen anybody try to use ClassName#qux for a property but perhaps that's possible too!
Hopefully this thread will help to set people on the straight and narrow!
Thanks in advance
P.S. it's hard searching Google for this. "#" = "hash" = "pound" and "::" = "double colon" = "T_PAAMAYIM_NEKUDOTAYIM"... and "hash" means something all of its own too, of course.
Edit: A further question is whether it is normal/correct to document properties and variables as ClassName::foo or ClassName::$foo (i.e. with or without a leading $)
Even for PHP, it's perverse, which is saying a lot. Don't ever do it in any context.
It is probably to disambiguate between actual static methods which can literally be called with Foo::bar(), and instance methods which require an object instance, like $foo->bar(). That's the only sensible explanation I can think of, and it's not an official standard in any context that I'm aware of.

How do I dynamically write a PHP object property name?

I have object properties in my code that look like this:
$obj ->field_name_cars[0];
$obj ->field_name_clothes[0];
The problem is I have 100s of field names and need to write the property name dynamically. Otherwise, the object name and the keys for the property will always be the same. So I tried:
$obj -> $field[0];
Hoping that the name of the property would dynamically be changed and access the correct values. But, I keep getting 'undefined property $field in stdClass::$field;
More or less I am trying dynamically write the php before it executes so that it can output the proper values. Thoughts on how to approach this?
Update for PHP 7.0
PHP 7 introduced changes to how indirect variables and properties are handled at the parser level (see the corresponding RFC for more details). This brings actual behavior closer to expected, and means that in this case $obj->$field[0] will produce the expected result.
In cases where the (now improved) default behavior is undesired, curly braces can still be used to override it as shown below.
Original answer
Write the access like this:
$obj->{$field}[0]
This "enclose with braces" trick is useful in PHP whenever there is ambiguity due to variable variables.
Consider the initial code $obj->$field[0] -- does this mean "access the property whose name is given in $field[0]", or "access the element with key 0 of the property whose name is given in $field"? The braces allow you to be explicit.
I think you are looking for variable-variable type notation which, when accessing values from other arrays/objects, is best achieved using curly bracket syntax like this:
$obj->{field[0]}
The magic method __get is you friend:
class MyClass
{
private $field = array();
public function __get($name)
{
if(isset($this->field[$name]))
return $this->field[$name];
else
throw new Exception("$name dow not exists");
}
}
Usage:
$myobj = new MyClass();
echo $myobj->myprop;
Explanation: All your field data is stored in a array. As you access $myobj->myprop that property obviously does not exists in the class. That is where __get is called. __get looks up the name in the field array and returns the correct value.
today i face that challenge. I ended up with that style of development
$countTickets = new \stdClass;
foreach ($tickets as $key => $value) {
if(!isset($countTickets->total)){
$countTickets->total = 0;
}
if(!isset($countTickets->{$value['categoryname']})){
$countTickets->{$value['categoryname']} = 0;
}
$countTickets->total += $value['number'];
$countTickets->{$value['categoryname']} += $value['number'];
}
I worked on some code that used dynamically created object properties. I thought that using dynamically created object properties was pretty cool (true, in my opinion). However, my program took 7 seconds to run. I removed the dynamic object properties and replaced them object properties declared as part of each class (public in this case). CPU time went from over 7 seconds to 0.177 seconds. That's pretty substantial.
It is possible that I was doing something wrong in the way I was using dynamic object properties. It is also possible that my configuration is broken in some way. Of course, I should say that I have a very plain vanilla PHP configuration on my machine.

Instantiate PHP object with string via factory

This is similar to Can PHP instantiate an object from the name of the class as a string?.
I'm using propel orm with PHP 5.2.17, and I want to store the name of a query class in the database, say "AuthorQuery", then use it to get a query object. There may be a different way to do this with propel, avoding the ::create() factory method. That solution would be welcome, but I'd rather to know if this is even possible with php (I won't be terribly surprised if the answer is "It's not").
Here's the problem. This will work:
$author_class = "Author";
$author = new $author_class();
Using the new keyword a string will get interpreted as the class name.
But I get syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM (that's referring to the ::) when I try to do it using a factory constructor instead:
$author_query_class = "AuthorQuery";
$author_query = $author_query_class::create(); // syntax error at the ::
Do I need an extra $ or something?
It turns out, this is not an issue for PHP 5.3+
Works exactly the way you describe (as far as I remember) with PHP5.3. However, if you still use 5.2, you can use reflection
$x = new ReflectionClass($author_query_class);
$author_query = $x->getMethod('create')->invoke(null);
Or just
$author_query = call_user_func(array($author_query_class, 'create'));
Worth to mention, that this is "much magic" and it will get hard to understand, what happens, when you have many of such constructions.
$author_query=call_user_func("$author_query_class::create");
This has to do with this line:
$author_query_class::create();
It is because (as quoted from the book PHP Master):
The double colon operator that we use for accessing static properties
or methods in PHP is technically called the scope resolution operator.
If there’s a problem with some code containing ::, you will often see
an error message containing T_PAAMAYIM_NEKUDOTAYIM. This simply refers
to the ::, although it looks quite alarming at first! “Paamayim
Nekudotayim” means “two dots, twice” in Hebrew.
You can do something like this in PHP 5.3 and more support is is on the table for PHP 5.4. Before PHP 5.2 you may have to use something like the other answers provided or , gulp, eval().

What's the point of writing : $foo = & new someClass();?

I am getting a deprecated warning because of a library I am using. The statement is the following :
$this->_ole =& new OLERead();
The thing is I don't see why one would want to use & new in an instantiation.
If I am not mistaken, the & operator tells PHP to copy the reference to the instance, and not the instance itself. But in that case, isn't it pointless to ask for a copy of a reference that isn't stored ?
But since I don't exactly know how new exactly works, maybe this was supposed to save some obscure garbage collection, or something like that.
What do you think about that ?
From the documentation:
As of PHP 5, the new operator returns a reference automatically, so assigning the result of new by reference results in an E_DEPRECATED message in PHP 5.3 and later, and an E_STRICT message in earlier versions.
The library you use was probably developed for PHP 4.
Helpful information about why this was used can also be found in the migration guide:
In PHP 5 there is a new Object Model. PHP's handling of objects has been completely rewritten, allowing for better performance and more features. In previous versions of PHP, objects were handled like primitive types (for instance integers and strings). The drawback of this method was that semantically the whole object was copied when a variable was assigned, or passed as a parameter to a method. In the new approach, objects are referenced by handle, and not by value (one can think of a handle as an object's identifier).
That's an idiom for PHP4 compatibility. Objects were passed as copies per default there, and this is a workaround to always have references to an instance.
In PHP4, new returned a value and not a reference.
This is not the case in PHP5.
If you write $this->_old =& new OLERead(); a changement of _ole in any object will updates all references to the new object.
This is not the case without & .
EDIT: And yes, in previous versions of PHP, object were passed by copy. At the end, this is quite hard to have a consistent behaviour accross versions.

Categories