What is the -> (forward arrow) operator in Wordpress/PHP? - php

I have downloaded a WordPress theme and in many places in the code I see the operator ->. It could be for example to retrieve a post ID like this:
$postID = $post->ID
I can't find what the arrow actually does in the background. Does it make a database call? Or is it simply fetching the ID from the $post variable, similar to $postID = $post['ID']?

The arrow operator -> is for accessing properties or method of an object.
Overhead of accessing properties is neglectible, but it's sometimes more comfortable to assign a property to a temporary variable, just because it shortens the source code. Example
$oPropValue = $objWithSpeakingName->propertyWithLongName;
However, it's often a good practice to save the return value of an method call to a temporary variable to avoid to much overhead. For example if the method performs a database query (and has no build-in caching), it would cause massive overhead to call the method over and over instead of calling it once an then reuse the value, f.e. in a loop.
$propValue = $objWithSpeakingName->doSomeWork();
while( ..condition.. ) {
// work with $propValue
}
But it also depends on how a method is used and what it's doing. If it takes arguments, you might need to call it repeatedly with changing parameters, in order to get the job done.
while(..condition..) {
$arg = .. // might change in the loop
$propValue = $objWithSpeakingName->doMoreWork( $arg );
}

in PHP -> simply means it is accessing object properties, like how '.' works in other Object Oriented Languages like java.

Related

Setting a property on a target object only if it exists in a source object, using a helper function

I'm writing a piece of data processing code that often has to set a property on a target object to the value of a property of a source object, but only if that property exists in the source object, like so:
if (property_exists($source, 'something')) {
$target->other = $source->something;
}
(I don't use isset() because null values should also be passed on.)
Repeating the above all over the code would be a pain. Right now I'm using this function to do it:
function set_if_exists($target, string $targetProperty, $source, string $sourceProperty)
{
if (property_exists($source, $sourceProperty)) {
$target->$targetProperty = $source->$sourceProperty;
}
}
which for the example above would be
set_if_exists($target, 'other', $source, 'something');
Is there a way to achieve the same without having to name the properties as strings? Ideally I would like to be able to do something like
set_if_exists($target->other, $source->something);
but I have no idea how to achieve this. Is it even possible?
array_key_exists only works on arrays, you are using objects. You should use the property_exists function to know if an object has a specific property.
You cannot do this the way you want to because a non-existing property will always return null, so there is no way to know if the property exists or not from the value.
I have concluded that this is not possible. There does not seem to be any mechanism in PHP that would allow you check for the existence of a (potentially deep) property, the way that the isset() builtin or ?? can.

Need to access associative array data created inside a class by json_decode from outside the class

I've been using procedural php for a long time but am still learning OOP. I was able to find a bit of code online that is in the form of a class and I am able to call a new instance of the class and use var_dump on a string to have it print JSON data to a web page. I can look at the results of the var_dump and see that it's returning exactly what I want. I'm then able to use json_decode on the same string to turn it into and associative array and then I can echo the values from within the class. The problem is, I need to use the array values in more code - it's great that I can confirm it by printing it to a web page but I need to use it... but I'm getting errors that state the array is undefined once I try to access it outside of the class.
I'm using this line to convert the data into an array:
$response_array = json_decode($body, true);
I've already confirmed that this works within the class by using this code to print some of the data:
echo $response_array['amount'];
and it works - I see it on the web page.
I've been using this code to create the new instance of the class:
$fdata = new FData();
$fdata->request($order_total, $cc_exp, $cc_number, $cc_name, $order_id, $customer_id);
(the function named 'request' is defined as a public function inside the class)
After that, I want to grab the $response_array so that I can store the returned data into a transactions table, i.e something like this:
$r = mysqli_query($dbc, "CALL add_transaction($order_id, $response_array['transaction_type'], $response_array['amount'], $response_array['exact_resp_code'], $response_array['exact_message'], $response_array['bank_resp_code'], $response_array['bank_message'], $response_array['sequence_no'], $response_array['retrieval_ref_no'], $response_array['transaction_tag'], $response_array['authorization_num'])");
but I keep getting an error saying that the array values are undefined.
Things I have already tried (and which failed) include:
Defining the variables as public inside the class, setting their value in the class, and then calling them outside the class...
public $amount = $response_array['amount'];
then using $amount in my procedure CALL --- I still get the error saying that $amount is undefined.
Using 'return', as in
return $response_array;
and still the error saying the values are undefined.
I tried embedding the entire rest of my code within the class, just copy/paste it in right after the json_decode... but for some reason it can't seem to then make the database calls and other things it needs to do.
I've been reading about __construct but I'm not sure if it applies or how to use it in this case...
I want to stress that I AM able to see the results I want when I use var_dump and echo from within the class.. I need to access the array created by json_decode OUTSIDE of the instance of the class.
Any advice would be greatly appreciated. Thanks.
Assuming your FData::request method ends with something like this...
$response_array = json_decode($body, true);
return $response_array;
and you call it like this...
$response_array = $fdata->request(...);
You should then be able to use $response_array in the calling scope.
Extra note; you should be using prepared statements with parameter binding instead of injecting values directly into your SQL statements.

Drupal - How can I make an array globally accessible?

I'm using this code in a views field template (in this case views-view-field--all-members--uid.tpl.php):
<?php
$users_friends = flag_friend_get_friends($user->uid);
$users_friends_ids = array();
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
?>
It basically gets the user ids of friends and puts them in an array so I can check if the field matches any of the user ids.
So my problem is that I don't want to have this within this template (for a few reasons), but if I don't I can't access the array. How can I make this array globally accessible?
Without knowing your "few reasons", I can't say if this is the answer for sure. My own reasons would probably be that I don't want the same code executing a bunch of times, and I'd rather not have the same exact code in multiple places.
I would then create a function with a static variable to hold the friends array.
function mymodule_get_friends_ids() {
// pull in the current global user variable
global $user;
// call up the static variable
static $users_friends_ids;
// return if this static var has already been set
if (is_array($users_friends_ids)) {
return $users_friends_ids;
}
// if we hit here, then this function has not been
// run yet for this page load.
// init array
$users_friends_ids = array();
// if user is anon, no need to go on
if (user_is_anonymous()) {
return $users_friends_ids;
}
// get friends array
$users_friends = flag_friend_get_friends($user->uid);
// build ids array
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
return $users_friends_ids;
}
Now in your templates, you can call mymodule_get_friends_ids() in as many places as you want, and the working code below the first return will only get executed the first time it is called.
Coder1's advice is very good - it keeps you from populating your global variable namespace with a lot of junk. It's probably the most "elegant." It might not be the easiest to use if you are rather new to PHP (which I'm guessing might be the case if it's hard to get your head around returning arrays, but that's ok).
However, if this is really a priority, you probably don't care about having one extra global variable.
I suppose I may be stating the obvious here - but you can, at pretty much any point in execution (provided the information you need has already been generated - e.g., the $user variable has been populated), do this:
$GLOBALS['users_friends_ids'] = /* your code goes here */
Then in your template, you access this by ...
$friendsArray = $GLOBALS['users_friends_ids'];
Or you can simply use the construct
global $user_friends_ids;
when you want to initialize the variable, or access it inside a function or class (which is the case for your template files - they are called inside functions, so you need to globalize or use the $GLOBALS array, which is "automagically" all of the variables active in the global namespace).
The most "logical" place to do this would be inside a module using one of the many hooks available, to execute this code only once. hook_init() might do it for you, if the user object is already loaded at this point (not sure, you'll have to test). But you might not want to figure out making Drupal modules (it's not that difficult).
If you are doing this inside a template (and though it's not good practice, many Drupal site owners with a beginning knowledge of PHP put everything in templates), you'll want to know which template code is being executed when. Node template code tends to be executed before page template code - which is logical, since otherwise the variables for node content in the page template wouldn't be populated.
If you have listings of nodes, they'll be calling this code multiple times, so you'll end up doing something similar to what Coder1 is describing. If you don't want to create your own small module, you could put the function declaration he's written in your theme's template.php file, since it's called only once. You don't want to put function declarations in the tpl.php files, since they are sometimes called more than once (and you aren't allowed to declare functions more than once).
If you have a hard time understanding the function and the return, you can always do something like this in your code (which is very, very inelegant - but it's better to have inelegant code that you do understand, than elegant code that's you don't).
if(!isset($GLOBALS['users_friends_ids'])) {
$GLOBALS['users_friends_ids'] = /* your code here */
}

method chain hijacking

This isn't a real fluent interface. I have an object which builds up a method stack. Which gets executed by a single function call. But now I might add another virtual method, which "takes over" that method stack.
Use case: I'm wrapping my superglobals into objects. This allows me to "enforce" input filtering. $_GET and co provide simple sanitizing methods. And my new version now allows chaining of atomic filters. As example:
$_GET->ascii->nocontrol->text["field"]
This is a method call. It uses angle brackets. But that's just a nice trick which eases rewriting any occourence of $_GET["field"]. Anyway.
Now there are also occasionally forms with enumerated fields, as in field[0],field[1],field[2]. That's why I've added a virtual ->array filter method. It hijacks the collected method stack, and iterates the remaining filters on e.g. a $_POST array value. For example $_POST->array->int["list"].
Somewhat shortened implementation:
function exec_chain ($data) {
...
while ($filtername = array_pop($this->__filter)) {
...
$data = $this->{"_$filtername"} ($data);
...
}
function _array($data) {
list($multiplex, $this->__filter) = array($this->__filter, array());
$data = (array) $data;
foreach (array_keys($data) as $i) {
$this->__filter = $multiplex;
$data[$i] = $this->exec_chain($data[$i]);
}
return $data;
}
The method stack gets assembled in the $this->__filter list. Above exec_chain() just loops over it, each time removing the first method name. The virtual _array handler is usually the first method. And it simply steals that method stack, and reexecutes the remainder on each array element. Not exactly like in above example code, but it just repeatedly repopulates the original method stack.
It works. But it feels kind of unclean. And I'm thinking of adding another virtual method ->xor. (YAGNI?) Which would not just iterate over fields, but rather evaluate if alternate filters were successful. For example $_REQUEST->array->xor->email->url["fields"]. And I'm wondering if there is a better pattern for hijacking a function list. My current hook list ($this->__filter) swapping doesn't lend itself to chaining. Hmm well actually, the ->xor example wouldn't need to iterate / behave exactly like ->array.
So specifically, I'm interested in finding an alternative to my $this->__filter list usage with array_pop() and the sneaky swapping it out. This is bad. Is there a better implementation scheme to executing a method list half part me -> half part you?
I've made a similar chaining interface before, I like your idea of using it on GET/POST vars.
I think you will be better off doing something like $var->array->email_XOR_url; rather than $var->array->email->XOR->url;. That way you can catch the various combinations with your __get/__call magic.

Getting database values into objects

The thing is that you have classes and then you have the database data. When you create an object how do you set the objects properties to contain the data in the database ?
I saw something like this and I'm wondering if this is really the best way to do it. I'm sure this is a fairly common issue, but I don't know what are the most accepted solutions on how to handle it.
In this example when the object is created you pass an id as a parameter and then you run a query to the database with the id and you assing the returned values to the object properties. I don't have much PHP experience and haven't seen this used much.
Is this an acceptable way to achieve this purpose ? Is there a better or more accepted way ?
public function __construct($id = null){
if($id != null){
$sql = "SELECT *
FROM users
WHERE user_id = $id";
$res = Db::returnRow($sql);
// $res contains an associative array with database columns and values
if($res){
$this->user_id = $res['user_id'];
$this->user_name = $res['user_name'];
//and so on...
}
}
}
Could somebody provide some sample code or pseudocode to illustrate what is the correct way to do this ?
It could be an acceptable way for a homework maybe. But architecturaly it is not.
Your class that is representing your business data (a user in your example) must be loosely coupled with your database access logic. In the end the PHP class acting as a user should not be aware that the data come from a database, a file or any other resource. Following that you will be able to reuse your user php class in other projects without having to change anything to it! If you have your data access logic inside it you are stuck.
Conclusion: I would suggest to read some resources on Design Pattern (in your situation take a look at DAO pattern) ;) Hint: the one from Head First series is extremely accessible and enjoyable.
You could create a function to do this for you automatically, by looping over the associative array's key/value pairs. Or you could look into using an ORM library.
Yes, you can semi-automate this by having a parent class all objects inherit from. On load, it queries, "SHOW FIELDS FROM [my tablename]" and populates an associative array with the names. If an id has been passed in, it looks for a valid object in that table with that id and assigns the values to the array.
Side note: don't pass your id directly into your query like that. Parametize the sql and wrap a function around any user input to sanitize it.
If it's mysql, you can just do:
$obj = mysql_fetch_object($query);
PDO the ability to use arbitrary classes as the target for a fetch, but beware that they assign the variable data before running the constructor:
$pdo->query($stmt, PDO::FETCH_CLASS, "MyClass", array('foo'=>'bar'));
...where the final parameter contains arguments for your class constructor.

Categories