Define local variables in another function - php

I've been looking at Magic Constants and Reflection in PHP to see if the following is possible:
function one() {
setVars();
// $node would be in scope
print_r($node);
}
function setVars() {
return $node = '2';
}
Is this a classical programming concept? Reflection seems to be the closest thing. Basically, I just want to define variables in a different scope (the scope/context of the function that called the setVars() function).

For more than one variable try to store them in a array and return the array.
function one() {
$nodeArray = setVars();
print_r($nodeArray );
}
function setVars() {
$nodeArray[] = 1;
$nodeArray[] = 1;
$nodeArray[] = 1;
return $nodeArray;
}

Take a look at extract().
function one() {
$vars = setVars();
extract($vars);
// $node1 would be in scope
print_r($node1);
}
function setVars() {
$node1 = '1';
$node2 = '2';
return compact('node1','node2');
}
It should be said, although this is possible, it often leads to terrible architecture and problems down the line.

Related

How do i get my class to use an array from outside the class?

I'm currently trying to get back into object oriented programming How do i get my array inside my class? Global doesn't seam to cut it.
<?
$systems = file_get_contents('https://api.eveonline.com/map/Sovereignty.xml.aspx');
$systems = explode("<row ",$systems);
//print_r($systems);
for ($i = 1; $i <= count($systems); $i++) {
//system name
$systemnames=explode("solarSystemName=",$systems[$i]);
$systemnames=explode('"',$systemnames[1]);
$systemnames=$systemnames[1];
//system id
$systemid=explode("solarSystemID=",$systems[$i]);
$systemid=explode('"',$systemid[1]);
$systemid=$systemid[1];
$systembyid[$systemid]=$systemnames;
$systembyname[$systemnames]=$systemid;
}
class Systems{
public function __construct()
{
global $systembyid;
global $systembyname;
}
function getSystems($system)
{
if (is_numeric($system) && $systembyid[$system]) {
return $systembyid[$system];
}
elseif($systembyname[$system]){
return $systembyname[$system];
}
else{
return "Error: Invalid system id or name";
}
}
}
?>
Try passing the values into the constructor like this, also if you use the & you are just passing a reference and not making a copy of the whole array.
class Systems{
private $sysyembyid;
private $systembyname;
public function __construct(&$systembyid, &$systembyname)
{
$this->systembyid = $systembyid;
$this->systembyname = $systembyname;
}
function getSystems($system){
if(is_numeric($system) && $this->systembyid[$system]){
return $this->systembyid[$system];
}
elseif($this->systembyname[$system]){
return $this->systembyname[$system];
}
else{
return "Error: Invalid system id or name";
}
}
}
I prefer to use Dependency Injection. Dependency Injection is when you inject your object's dependencies via the constructor. This ensures that the object will have its dependencies at creation.
class Systems {
protected $systembyid;
protected $systembyname;
public function __construct($systembyid, $systembyname)
{
$this->systembyid = $systembyid;
$this->systembyname = $systembyname;
}
public function getSystems($system) {
//Access them with $this-> like below
$this->systembyid[$system];
$this->systembyname[$system];
}
}
Note If you want to be able to modify $systembyid and $systembyname outside of the class, and see the changes within the class, you can pass references to __construct() instead, by specifying the parameters as references:
public function __construct(&$systembyid, &$systembyname)
{
$this->systembyid = $systembyid;
$this->systembyname = $systembyname;
}
Alternatively, you can pass them as parameters to your getSystems() method.
class Systems() {
public function getSystems($system, $systembyid, $systembyname) {
//Do stuff
}
}
The main drawbacks with this approach is that you always have to pass them as parameters to the method, and the method signature could get quite long.
You either need to use the global key word with var in the function where you use it, in this case getSystems() (bad) or pass them into the constructor or the function where you use them, or set them:
Probably the most common case:
public function __construct($s1, $s2)
{
$this->systembyid = $s1
$this->systembyname = $s2
}
//then use $this->systembyid etc in other functions
Or better yet, why not put all that processing code in a function off the class like processSystems() and set the vars there:
public function processSystems($file) {
$systems = file_get_contents($file);
$systems = explode("<row ",$systems);
//print_r($systems);
for ($i = 1; $i <= count($systems); $i++) {
//system name
$systemnames=explode("solarSystemName=",$systems[$i]);
$systemnames=explode('"',$systemnames[1]);
$systemnames=$systemnames[1];
//system id
$systemid=explode("solarSystemID=",$systems[$i]);
$systemid=explode('"',$systemid[1]);
$systemid=$systemid[1];
$systembyid[$systemid]=$systemnames;
$systembyname[$systemnames]=$systemid;
}
$this->systembyid = $systemnames;
$this->systembyname = $systemid;
}
Aside from that, I would say look into simple_xml or DOM for the XML parsing.
Also, you are storing the exact same data in each array. Just use one and either lookup the key or the value.

Return reference to parameter

is any way to return reference at class parameter or global variable? I try this
class test{
public static $var;
public static function get(&$ref){
$ref = self::$var;
}
}
test::get($ref);
$ref = 'test';
var_dump(test::$var);
it's a basic example, i know, then this example can be use another way, but i need to keep principle
this is my function, where is problem with reference to variable
class mySession{
public static function issetKeys(){
$keys = func_get_args();
$session = &$_SESSION;
$c = 0;
if (is_array($keys)){
foreach ($keys as $val){
if (isset($session[$val])){
$session = &$session[$val];
$c++;
}
else break;
}
}
return $c == count($keys);
}
public static function &get(){
$keys = func_get_args();
$session = &$_SESSION;
if (is_array($keys)){
foreach ($keys as $val){
if (!isset($session[$val])) $session[$val] = Array();
$session = &$session[$val];
}
}
return $session;
}
}
function getValue(){
if (!mySession::issetKeys('p1', 'p2')){
$session = mySession::get('p1', 'p2');
$session = 'string';
}
return mySession::get('p1', 'p2');
}
print_r($_SESSION);
but no variable save in to $_SESSION
No, and why would you ever do such a thing?
If you want to access a public static variable, you'll just write
test::$var = "Hello there handsome";
In the case above you're not passing the reference of this::$var onto $ref, you're letting a reference to $ref contain the value of this::$var. PHP is not C, and references should generally be avoided when not necessary in PHP.
In the general case, a parameter only exists for the duration of the function to which it was passed; when the function returns, the call stack is unwound and the parameter disappears, which means that any reference to a variable that lived in the call stack will no longer be valid (since it points to memory which has been freed and now quite possibly contains something else entirely.)
That said, it is possible to return a reference to a parameter, although this will not work if you try to return a reference to a variable that actually lives in the stack (that is, one that was not passed by reference):
$myGlobal = 10;
// Note the & before the function name
function &returnReference(&$x) {
return $x;
}
// Note the & before the function call
$someValue = &derp($myGlobal);
echo $myGlobal;
$someValue = 0;
echo $myGlobal;

Use a var to describe a var of a class

Basically I want to access a variable of a class, but I change the name of the wanted variable dynamically. I'm having a bit problems to explain exactly, but see my code, maybe it gets more clear:
$requirement = array('req1','req2');
foreach($requirements as $requirement)
{
// CHECK FOR REQUIRED PARAMETERS
if(!isset($this->$requirement)) { echo 'foo'; }
}
So I actually want to access $this->req1 and so on, but how do I access it with my iterator-variable? I'm not sure whether this is right already, having difficulties to find out.
Also: How would I access a parents` variable in the same situation ?
$$ (or use magic getters/setters)
if(!isset($this->$$requirement)) { echo 'foo'; }
or
if(!isset($this->{$requirement})) { echo 'foo'; }
I would use magic getters and setters, as Mark said. Like this:
<?php
class MyClass
{
protected $data;
public function __get($key)
{
return $this->data[$key]
}
public function __set($key, $value)
{
$this->data[$key] = $value;
}
}
$var = 'adsdas';
$var2 = 'sadkajds';
$obj = new MyClass;
$obj->$var = 1;
$obj->$var2 = 1;

PHP closure scope problem

Apparently $pid is out of scope here. Shouldn't it be "closed" in with the function? I'm fairly sure that is how closures work in javascript for example.
According to some articles php closures are broken, so I cannot access this?
So how can $pid be accessed from this closure function?
class MyClass {
static function getHdvdsCol($pid) {
$col = new PointColumn();
$col->key = $pid;
$col->parser = function($row) {
print $pid; // Undefined variable: pid
};
return $col;
}
}
$func = MyClass::getHdvdsCol(45);
call_user_func($func, $row);
Edit I have gotten around it with use: $col->parser = function($row) use($pid). However I feel this is ugly.
You need to specify which variables should be closed in this way:
function($row) use ($pid) { ... }
You can use the bindTo method.
class MyClass {
static function getHdvdsCol($pid) {
$col = new PointColumn();
$col->key = $pid;
$parser = function($row) {
print $this->key;
};
$col->parser = $parser->bindTo($parser, $parser);
return $col;
}
}
$func = MyClass::getHdvdsCol(45);
call_user_func($func, $row);
I think PHP is very consistent in scoping of variables. The rule is, if a variable is defined outside a function, you must specify it explicitly. For lexical scope 'use' is used, for globals 'global' is used.
For example, you can't also use a global variable directly:
$n = 5;
function f()
{
echo $n; // Undefined variable
}
You must use the global keyword:
$n = 5;
function f()
{
global $n;
echo $n;
}

Static variable for optimization

I'm wondering if I can use a static variable for optimization:
public function Bar() {
static $i = moderatelyExpensiveFunctionCall();
if ($i) {
return something();
} else {
return somethingElse();
}
}
I know that once $i is initialized, it won't be changed by by that line of code on successive calls to Bar(). I assume this means that moderatelyExpensiveFunctionCall() won't be evaluated every time I call, but I'd like to know for certain.
Once PHP sees a static variable that has been initialized, does it skip over that line of code? In other words, is this going to optimize my execution time if I make a lot of calls to Bar(), or am I wasting my time?
I find it easier to do something like the code below. That way the caching is done globally instead of per implementation of the function.
function moderatelyExpensiveFunctionCall()
{
static $output = NULL;
if( is_null( $output ) ) {
//set $output
}
return $output;
}
static $i = blah() won't compile, because php doesn't allow expressions and function calls in static initializers. You need something like
function foo() {
static $cache = null;
if(is_null($cache)) $cache = expensive_func();
do something with $cache
}
This should work in your (quite simple) case:
function your_function() {
static $output;
if (!isset($output)) {
$output = 'A very expensive operation';
}
return $output;
}
As for a global caching mechanism, you may use a method similar to this one.
Here is quite shorter approach:
function stuff()
{
static $smthg = []; // or null, or false, or something else
if ($smthg) {
return $smthg;
}
// filling $smthg goes here
// with a lot of
// code strings
return $smthg;
}
How about:
if (!isset($i))
{
static $i = moderatelyExpensiveFunctionCall();
}

Categories