How to avoid repeatedly calling a function in this case? - php

I wrote a function to display an object on each wordpress post:
function pod(){
global $post,$pod;
$id = get_the_ID();
$pod = new WP_POD( $id );
return $pod;
}
I thought $pod is global, so, I can use $pod->stuffs when need, but it doesn't work.
So, in each function I need to use stuffs in the object, I have to add one line:
$pod = pod()
I think repeatedly calling this function might not good for performence. Is there a way to make this global and accessable by other functions?

You want to avoid the global keyword. If you need to pull in data to a function, its a sure sign that your design is broken (and Wordpress is broken). Use Dependency Injection and pass in $post and $pod to the function (that will also prevent spooky action at a distance):
function pod($post, $pod)
{
$id = get_the_ID();
$pod = new WP_POD( $id );
return $pod;
}
However, that still doesnt make much sense. You are not using $post within the function, so why pass it in? Instead, you reach out of the function scope again to fetch some sort of id. And you use that to instantiate a WP_POD instance and assign it back to the global scope.
Why not just do
function createPod($id)
{
return new WP_POD($id);
}
and then call it with
$pod = createPod(get_the_ID());
or just delete the function altogether and just do
$pod = new WP_POD(get_the_ID());
Yes, that wont assign the $pod instance to the global scope, but I doubt that you really need it there anyways.
As for performance: you should not worry about performance unless you have profiled your application and found that it's running slow and that particular code is indeed the reason for it being slow.

You could simply pass the object to the functions you're calling.
Or use something else related to http://en.wikipedia.org/wiki/Dependency_injection
Or, if that doesn't convince you ;-), at least limit the visibilty of the variable via something like
function pod($init=false) {
global $post,$pod;
static $pod=null;
if ( is_null($pod) || $init ) {
$id = get_the_ID();
$pod = new WP_POD( $id );
}
return $pod;
}
see http://docs.php.net/language.oop5.static

You need to delcare $pod as global in the function you are trying to access the variable from. Variables are not accessible globally unless explicitly declared in PHP unlike most other languages.
Call pod() once
then access like this
global $pod;
$pod->stuffs ....

You can use $GLOBALS to declare the variable in your script:
$pod = new WP_POD( get_the_ID() );
function myFunc() {
$GLOBALS['pod']->aMethod;
}

Related

Class-Wide accessible static array, trying to push to it, but keeps coming back empty

class UpcomingEvents {
//Variable I'm trying to make accessible and modify throughout the class methods
private static $postObjArr = array();
private static $postIdArr = array();
private static $pinnedPost;
//My attempt at a get method to solve this issue, it did not
private static function getPostObjArr() {
$postObjArr = static::$postObjArr;
return $postObjArr;
}
private static function sortByDateProp($a, $b) {
$Adate = strtotime(get_field('event_date',$a->ID));
$Bdate = strtotime(get_field('event_date',$b->ID));
if ($Adate == $Bdate) {
return 0;
}
return ($Adate < $Bdate) ? -1 : 1;
}
private static function queryDatesAndSort($args) {
$postQuery = new WP_Query( $args );
if( $postQuery->have_posts() ) {
while( $postQuery->have_posts() ) {
$postQuery->the_post();
//Trying to push to the array, to no avail
array_push(static::getPostObjArr(), get_post());
}
}
//Trying to return the array after pushing to it, comes back empty
return(var_dump(static::getPostObjArr()));
//Trying to sort it
usort(static::getPostObjArr(), array(self,'sortByDateProp'));
foreach (static::getPostObjArr() as $key => $value) {
array_push(static::$postIdArr, $value->ID);
}
}
}
I'm trying to access $postObjArr within the class, and push to it with the queryDatesAndSort(); method. I've tried a couple of things, most recent being to use a get method for the variable. I don't want to make it global as it's bad practice I've heard. I've also tried passing by reference I.E
&static::$postObjArr;
But when it hits the vardump, it spits out an empty array. What would be the solution and best practice here? To allow the class methods to access and modify a single static array variable.
static::$postObjArr[] = get_post()
I didn't think it would of made a difference, but it worked. Can you explain to me why that worked but array.push(); Did not?
Arrays are always copy-on-write in PHP. If you assign an array to another variable, pass it into a function, or return it from a function, it's for all intents and purposes a different, new array. Modifying it does not modify the "original" array. If you want to pass an array around and continue to modify the original array, you'll have to use pass-by-reference everywhere. Meaning you will have to add a & everywhere you assign it to a different variable, pass it into a function, or return it from a function. If you forget your & anywhere, the reference is broken.
Since that's rather annoying to work with, you rarely use references in PHP and you either modify your arrays directly (static::$postObjArr), or you use objects (stdClass or a custom class) instead which can be passed around without breaking reference.

Using a function in php - what am I doing wrong?

$users = [
"Andrew",
"Max",
"Larry",
"Ricardo",
"Lucy",
"Marcus",
"Sophie"
];
$sector_rel = [];
$location_rel = [];
function sectorRel($user){
return sector_rel[] = round(1/rand(1,10),3);
}
function locationRel($user){
return $location_rel[] = round(1/rand(1,20),3);
}
foreach($users as $user){
sectorRel($user);
locationRel($user);
}
This:
function sectorRel($user){
return sector_rel[] = round(1/rand(1,10),3);
}
Should be/could be:
function sectorRel($user){
global sector_rel;
sector_rel[] = round(1/rand(1,10),3);
}
The problem is that the functions don't have access to the array variables. You can import them into the function scope using the keyword global, if they are indeed global variables. Now, having global variables isn't a good thing, and for a small test it's okay, but eventually you'll be eliminating your globals and this solution won't work.
But alternatively, you could pass the array variables to the function as an argument. However, this still introduces a lot of logic in the function. The function has to be told about the array, it must know that it needs to add a value to the end, and it also needs to calculate the actual value to add.
So better, make the function just return the calculated value and add it to the array outside of the function:
function sectorRel($user){
// Assuming your are going to use 'user' here somewhere?
return round(1/rand(1,10),3);
}
function locationRel($user){
return round(1/rand(1,20),3);
}
foreach($users as $user){
sector_rel[] = sectorRel($user);
$location_rel[] = locationRel($user);
}
You can then wrap this entire snippet of code into another function and call that to populate the arrays. That way, you've quite reasonably split the responsibilities of the functions and have a piece of code that looks nice and clean.
You do not need to use return in either of sectorRel or locationRel. At the moment this will return the reference to that array and it is not being stored in a variable. You would need to store them in a variable or just get rid of the return. My PHP is a little weak at the moment but you should probably append the values in those functions to the array.
Also if you have a parameter called $user for each of those functions you should either use that parameter or just get rid of it.

extract method into template with global scope, something similar to extract function

I create my mini-micro framework. In my class which loads template I have property named $variable. This property stores array of viariables which should be available in my template.
For example:
$this->variable = array($key=>5, $data=>10);
Next, I use function extract()
extract($this->variable);
So, now in my template(test.html.php) I have simple access to passed variables:
test.html.php
echo $key;
I also have method named import().
In my template I have access for this method by operator $this
test.html.php
$this->import();
Is there any possibility to call my function import() in template, without operator $this?
Have your template implement the __invoke() magic method.
class Template {
......
public function __invoke() {
$this->import();
}
}
Set a variable named import which is equal to $this.
$this->variable['import'] = $this;
When you extract the variables a variable named $import will be available and if you do $import() in the template it should call the __invoke() method of the template class which in turn calls the import() method of the class.
You should try and refrain from calling methods in templates though if possible. You should just be dealing with variables. A little call to $import() somewhere in there may not be the worst thing in the world, it depends what that method is doing.
If you can, please try to avoid using extract() and the global scope.
be careful, when using extract()
extract() is a very dynamic language feature, which tends to cause clashes with variables already existing in the local scope. You have to take care of that by using the second
parameter, which controls the newly created variables.
(EXTR_SKIP) including not overwriting any existing variables ,
(EXTR_IF_EXISTS) ONLY overwriting existing variables (so you can create a whitelist)
(EXTR_PREFIX_ALL) or by adding prefixes to the variables
extract() causes developer confusion, because new developers on your project, simply don't grasp were variables are coming from.
extract() is also a performance killer, in regards to using it with HHVM, because of the extra book-keeping of scoped-variables, which needs to be done. In short: avoid it, when optimizing for speed on HHVM.
Still it's common practice to use extract in the View object, like so:
using extract() in a View object
// View.php
class View {
public $variables;
function render($filename) {
extract($this->variables);
ob_start();
$this->returned = include($this->dir . $this->filename);
return ob_get_clean();
}
}
// test.php
$view = new View;
$view->variables = array('test' => 'Hello World!');
$template = __DIR__.'/test.tpl';
echo $view->render($template);
// var_dump($view->returned); // to see included template content
// Template: test.tpl
<p><?php echo $test; ?></p>
If you really want to pollute the global scope:
Merge Variable to $GLOBALS
$GLOBALS += $vars;
function globalize($data) {
$GLOBALS += $data;
}
$vars = array('a' => 1, 'b' => 2);
globalize($vars);
echo $a; // prints 1
foreach with creating dynamic global variables from key names
foreach($array as $var_name => $var_value)
{
global $$var_name;
$$var_name = $var_value;
}
or better (to avoid clashes) directly add to GLOBALS array.
foreach($array as $var_name => $var_value)
{
$GLOBALS[$var_name] = $var_value;
}
Works, but is evil...

Resolve member properties without using "$this->"?

Given a basic object like the following my inclination (based on working with AS3) is that $friend could be interpreted $this->friend but the PHP parser only sees $friend as an uninitialized variable localized to the holler function. Is there a way to access member variables without using $this->? My goal is to discover the leanest possible syntax.
class MyBuddy
{
private $friend = true;
public function holler()
{
if ( $friend ) // <- parser won't resolve $friend to a member variable
return 'Heeeeey Buuuuuday!';
else
return null;
}
}
Update: After considering the answers given it seems that the most concise and easy to understand approach is to pass the instance variable by reference to a function level variable at the top of a function. It's a decent solution for functions which reference verbose instance variables.
// Demonstrating a simple cache which abbreviates $this->thingCollection
// to $things for the function body
public function getThing( $id, $qty )
{
$things = &$this->thingCollection; // <-- pass by reference
if ( empty($things) )
$things = [];
if ( empty($things[$id]) )
$things[ $productId ] = [];
if ( empty($things[ $id ][ $qty ]) )
$things[ $id ][ $qty ] = get_thing_from_database( $id, $qty );
return $things[ $id ][ $qty ];
}
Do not invent clever workarounds that developers maintaining the code after you will have a hard time understanding. The way PHP does it is using $this, and you should embrace the conventions of language.
The issue is that php doesn't consider them one in the same, thus allowing a specific method to have a local variable with that properties name. For instance:
class MyBuddy
{
private $friend = true;
public function holler($friend)
{
if ($this->friend == $friend ) // <- parser won't resolve $friend to a member variable
return 'Heeeeey Buuuuuday!';
else
return null;
}
}
define("HELL_NAW", false);
define("MMM_HMMM", true);
$hombre = new MyBuddy();
echo $hombre -> holler(HELL_NAW);
$l_jessie = new MyBuddy();
echo $l_jessie -> holler(MMM_HMMM);
So to get what you're after, you could go with:
public function holler()
{
$friend = $this ->friend;
if ($friend )
return 'Heeeeey Buuuuuday!';
else
return null;
}
But that might be called the opposite of lean. But it does also illustrate the point (and Alex's) that php isn't set up with your Responsibility Principle in mind and you'll end up doing more work to make things harder for the next guy to achieve a goal based on principle but will appear to be aesthetic to anyone else.
On the other hand, php does have the magic methods __get() and __set() which allow for referencing non-defined or inaccessible properties by defining how they are handled. With that, you wouldn't need to reference $this->friend since it doesn't exist. Just reference the argument for the method (which is handy but will again just make things a cluster-bate to look at).
I am sympathetic to your question because I almost posted it myself. This is a case in which what you want to do is more readable to you, but won't be to another PHP developer expecting standard use of $this-> when targeting class level objects.

PHP Function named after the Value of a Variable

I have a PHP function that I need to create that executes PHP or HTML Code that is stored in a variable. That's one problem. Another problem is the fact that the function will be created multiple times and will need a unique name so I've named it after $title but I'm not sure if this will create the function from the value of $title or if it will create a function called $title or if it just won't work. This is my code:
$title = $_POST['sogo_aso_name'];
$output = $_POST['sogo_aso_output'];
Some Code Here...
function $title ($output)
{
//Some Code Here to execute $output...
}
So... That's my problem. I'm not sure what will execute the $output cleanly so it can be shown on a page. And I don't know if the function will be named after the value of $title
Thanks for any help!
Ethan Brouwer
You can use call_user_func like this:
call_user_func($title, $output);
But it's really strange to change name of one function.
What you're trying to do is unfortunately not possible. You could create namespaces if you need a common name to prefix your functions with.
namespace fArr {
function func1 (args) {}
function func2 (args) {}
}
To call them you can use:
namespace {
fArr\func1($title, $output);
}
Generally you want to avoid creating totally anonymous functions. Maybe create a function that handles the title and output for all requests. Alternatively create a new object with the func name as a property and output assigned to it.
$title = $_POST['sogo_aso_name'];
$output = $_POST['sogo_aso_output'];
// Store data in an object named after the value of $title
// Note that constant use of this can get very messy, and very confusing
$$title = (object) array('output' => $output);

Categories