If I have code like this
$myFunction = new classFoo(); //ie. class
$myFunction-> new functionBar($value1,$value2,$value3); //ie. function
I understand in a normal scenario, if I had this function...
function functionBar($value1,$value2,$value3){
$answer=$value1+$value2+$value3
return $answer
}
I could then plug into it like this
$answer=functionBar(1,2,3)
I could expect an echo of $answer to be 6, correct?
If I'm wrong there let me know, because my real issue is that the function is wrapped in a variable, which if I examine through console has what I need in it, but I can't get my head around how to access it with that extra layer involved.
because my real issue is that the function is wrapped in a variable
[snip] but I can't get my head around how to access it with that extra
layer involved.
Using your code and var names, and I've added the function which you do understand inside the class (is simply a function (aka "method") which essentially does the same thing - there are differences but not within the scope of your question).
It returns a value, which you can "wrap" (store) in a variable just the same as the function does without the class:
$myFunction = new foo();
$answer = $myFunction->functionBar(10, 20, 30);
class foo
{
public function functionBar($value1, $value2, $value3)
{
return $value1 + $value2 + $value3;
}
}
Your $answer var would contain "60". echoing it out would echo "60".
Related
It was kind of hard for me to form this as a title. Basically what I have is a simple laravel-like router that saves allowed locations in an array. My question is if I could supply some arguements dynamically through that array's elements. I think I did even worse in the body of the question so let me just give a simple example:
class Example(){
public function display($bool){
if($bool){
echo 'hey';
}else{
echo 'bye';
}
}
}
Now if you wanna call this class' method from somewhere else with a variable
$var = 'display';
$example = new Example();
$example->$var(true);
And you get 'hey', but what if I can only control the $var = 'display' part, and the code below is beyond my control. Can I still pass a value to that method? Something like
$var = 'display(true)';
$example = new Example();
$example->$var;
Not without some epic string parsing.
More importantly, if you need this, something that you're doing is horribly wrong.
Lets say we have function:
function foo() {
return "bar";
}
Is it possible to add some filter to foo() function, for example to make it returning double value like "barbar" without changing the function itself.
So we would have:
foo(); //returns "bar"
function filter($&val) {
$val = $val . $val;
}
add_filter_to_function('foo','filter');
foo(); //returns "barbar"
And then anywhere foo() is used, it would return filtered value without changing code that calls foo() to something like foo() . foo() and without changing the function itself
In PHP, there is a RunKit extension (runkit_function_redefine() in particular for your question) which allow you to manipulate with code's objects (such as function or classes) on the fly.
But I think you're doing something wrong if you need to change your function's code on that way - so may be you should reconsider your goal and resolve your original problem with another tools.
If you need to call your function with some parameters in some special cases, you can use something like:
function foo($x, $y)
{
//do stuff
}
function bar($x, $y, $z)
{
//do stuff with $z?
foo($x, $y);
}
and use bar() instead of foo() then - in certain places (which you need to adjust)
You cannot internally change the return value of a function, if it's static.
If you had foo($var), you could change the state of $var, and everytime you call foo($var) lately, you would recieve the new value, but in your case it's almost not possible.
You have to call the other function everytime you need double value:
function foo() {
return 'bar';
}
function filter($func) {
return $func.$func;
}
echo filter(foo());
Turn your function into an object method and then the add_filter_to_function would add the filter to the object.
Then when you called the function it would be able to use the filters that have been assigned to the object the function belongs to.
You could simply concatenate the value on itself:
$val = foo();
$val .= $val;
or if your function really needs to have a double value returned, then you should probably look at refactoring your foo() function, because it doesn't seem to do what you want.
Either that, or accept one of the other answers that tells you to wrap foo() around another function.
I have been told that a class cannot be defined within a class in PHP. However, in my own example this seems to work which has me confused:
class_test.php:
require('class_1.php');
new class_1
//Need $missing_variable here.
class_1.php
class class_1{
public function function_1(){
function callback_function(){
echo "A Callback";
$missing_variable = "Where Did I Go?";
}
require('class_2.php');
new class_2('callback_function');
}
public function __construct(){
$this->function_1();
}
}
class_2.php
class class_2{
public function __construct($callback){
echo "Hello World - ";
call_user_func($callback);
}
}
Loading class_test.php prints out
Hello World - A Callback
Question: How do I define $missing_variable such that I can get it where I need it?
In case anyone in the future has a similar problem, however unlikely that may be, I want to link to the codepad from below that shows the $missing_variable echo'd from outside the classes:
http://codepad.org/tRk0XWG7
Thanks again everyone.
Note: This is a follow up.
You can declare a class within a function. That's known as conditional declaration, i.e. only if the function is called will the class be declared. It doesn't make much of a difference then whether you include a file with the class declaration or if you type out the code inside the function.
This does not mean however that the classes share any sort of scope or data. Only the declaration is conditionally nested, it still has the same functionality and scope as explained before.
Your confusion about the callback can be explained by the same thing. When class_1::function_1 is executed the first time, the function callback_function is being defined. This is a regular global function that can be called from anywhere. It's not bound to the class in any way. You will also notice that you cannot execute class_1::function_1 a second time, PHP will complain that callback_function already exists when you're trying to declare it again.
As for the comment in the source code //How do I declare this variable so that it is available where I need it?: You don't. That variable is a local variable inside a function. It's only in scope inside the function. You can return its value from the function like any other return value if you want to. (You could make it global, but for the love of god don't!) If you need that value somewhere else, don't declare it as a variable inside a function, because only the function can access it then.
You would return $missing_variable in a few places. See below. (This isn't the only way to do it, mind you)
http://codepad.org/tf08Vgdx
<?
class class_2{
public function __construct($callback){
echo "Hello World - ";
$missing = $callback();
$this->missing = $missing;
}
}
class class_1{
public function function_1(){
function callback_function(){
echo "A Callback. ";
$missing_variable = "Where Did I Go?";
return $missing_variable;
}
$class2 = new class_2('callback_function');
return $class2->missing;
}
public function __construct(){
$this->missing = $this->function_1();
}
}
$class = new class_1();
echo $class->missing;
The main function of the example class uses the reusableFunction twice with different data and attempts to send that data to a different instance variable ($this->result1container and $this->result2container) in each case, but the data doesn't get into the instance variables.
I could get it to work by making reusableFunction into two different functions, one with array_push($this->result1container, $resultdata) and the other with array_push($this->result2container, $resultdata), but I am trying to find a solution that doesn't require me to duplicate the code.
My solution was to try to pass the name of the result container into the function, but no go. Does somebody know a way I could get this to work?
Example Code:
Class Example {
private $result1container = array();
private $result2container = array();
function __construct() {
;
}
function main($data1, $data2) {
$this->reusableFunction($data1, $this->result1container);
$this->reusableFunction($data2, $this->result2container);
}
function reusableFunction($data, $resultcontainer) {
$resultdata = $data + 17;
// PROBLEM HERE - $resultcontainer is apparently not equal to
// $this->result1container or $this->result2container when I
// try to pass them in through the parameter.
array_push($resultcontainer, $resultdata);
}
function getResults() {
return array(
"Container 1" => $this->result1container,
"Container 2" => $this->result2container);
}
}
(If this is a duplicate of a question, I apologize and will happily learn the answer from that question if somebody would be kind enough to point me there. My research didn't turn up any answers, but this might just be because I didn't know the right question to be searching for)
It looks to me like you want to be passing by reference:
function reusableFunction($data, &$resultcontainer) {
...
If you don't pass by reference with the & then you are just making a local copy of the variable inside reuseableFunction .
You are changing the copy, not the original. Alias the original Array by referenceDocs:
function reusableFunction($data, &$resultcontainer) {
# ^
And that should do the job. Alternatively, return the changed Array and assign it to the object member it belongs to (as for re-useability and to keep things apart if the real functionality is doing merely the push only).
Additionally
array_push($resultcontainer, $resultdata);
can be written as
$resultcontainer[] = $resultdata;
But that's just really FYI.
You may pass the attributes name as a String to the method like this:
function reusableFunction($data, $resultcontainer) {
$resultdata = $data + 17;
array_push($this->{$resultcontainer}, $resultdata);
}
//..somewhere else..
$this->reusableFunction($data, 'result2Container')
Some php experts wrote some texts about "why you shouldn't use byReference in php".
Another solution would be to define the containers as an array. Then you can pass an "key" to the method that is used to store the result in the array. Like this:
private $results = array();
function reusableFunction($data, $resIdx) {
$resultdata = $data + 17;
array_push($this->$results[$resIdx], $resultdata);
}
//..somewhere else..
$this->reusableFunction($data, 'result2Container');
//..or pass a number as index..
$this->reusableFunction($data, 1);
Anyone has an idea if this is at all possible with PHP?
function foo($var) {
// the code here should output the value of the variable
// and the name the variable has when calling this function
}
$hello = "World";
foo($hello);
Would give me this output
varName = $hello
varValue = World
EDIT
Since most people here 'accuse' me of bad practices and global variables stuff i'm going to elaborate a little further on why we are looking for this behaviour.
the reason we are looking at this kind of behaviour is that we want to make assigning variables to our Views easier.
Most of the time we are doing this to assign variables to our view
$this->view->assign('products', $products);
$this->view->assign('members', $members);
While it would be easier and more readable to just be able to do the following and let the view be responsible to determining the variable name the assigned data gets in our views.
$this->view->assign($products);
$this->view->assign($members);
Short answer: impossible.
Long answer: you could dig through apd, bytekit, runkit, the Reflection API and debug_backtrace to see if any obscure combination would allow you to achieve this behavior.
However, the easiest way is to simply pass the variable name along with the actual variable, like you already do. It's short, it's easy to grasp, it's flexible when you need the variable to have a different name and it is way faster than any possible code that might be able to achieve the other desired behavior.
Keep it simple
removed irrelevant parts after OP edited the question
Regardless of my doubt that this is even possible, I think that forcing a programmer on how to name his variables is generally a bad idea. You will have to answer questions like
Why can't I name my variable $arrProducts instead of $products ?
You would also get into serious trouble if you want to put the return value of a function into the view. Imagine the following code in which (for whatever reason) the category needs to be lowercase:
$this->view->assign(strtolower($category));
This would not work with what you're planning.
My answer therefore: Stick to the 'verbose' way you're working, it is a lot easier to read and maintain.
If you can't live with that, you could still add a magic function to the view:
public function __set($name, $value) {
$this->assign($name, $value);
}
Then you can write
$this->view->product = $product;
I don't think there is any language where this is possible. That's simply not how variables work. There is a difference between a variable and the value it holds. Inside the function foo, you have the value, but the variable that held the value is not available. Instead, you have a new variable $var to hold that value.
Look at it like this: a variable is like a bucket with a name on it. The content (value) of the variable is what's inside the bucket. When you call a function, it comes with its own buckets (parameter names), and you pour the content of your bucket into those (well, the metaphor breaks down here because the value is copied and still available outside). Inside the function, there is no way to know about the bucket that used to hold the content.
What you're asking isn't possible. Even if it was, it would likely be considered bad practice as its the sort of thing that could easily get exploited.
If you're determined to achieve something like this, the closest you can get would be to pass the variable name as a string and reference it in the function from the $GLOBALS array.
eg
function this_aint_a_good_idea_really($var) {
print "Variable name: {$var}\n";
print "Variable contents: {$GLOBALS[$var]}\n";
}
$hello="World";
this_aint_a_good_idea_really('hello');
But as I say, that isn't really a good idea, nor is it very useful. (Frankly, almost any time you resort to using global variables, you're probably doing something wrong)
Its not impossible, you can find where a function was invoked from debug_backtrace() then tokenize a copy of the running script to extract the parameter expressions (what if the calling line is foo("hello $user, " . $indirect($user,5))?),
however whatever reason you have for trying to achieve this - its the wrong reason.
C.
Okay, time for some ugly hacks, but this is what I've got so far, I'll try to work on it a little later
<?php
class foo
{
//Public so we can test it later
public $bar;
function foo()
{
//Init the array
$this->bar = array();
}
function assign($__baz)
{
//Try to figure out the context
$context = debug_backtrace();
//assign the local array with the name and the value
//Alternately you can initialize the variable localy
//using $$__baz = $context[1]['object']->$__baz;
$this->bar[$__baz] = $context[1]['object']->$__baz;
}
}
//We need to have a calling context of a class in order for this to work
class a
{
function a()
{
}
function foobar()
{
$s = "testing";
$w = new foo();
//Reassign local variables to the class
foreach(get_defined_vars() as $name => $val)
{
$this->$name = $val;
}
//Assign the variable
$w->assign('s');
//test it
echo $w->bar['s'];
}
}
//Testrun
$a = new a();
$a->foobar();
impossible - the max. ammount of information you can get is what you see when dumping
debug_backtrace();
Maybe what you want to do is the other way around, a hackish solution like this works fine:
<?php
function assign($val)
{
global $$val;
echo $$val;
}
$hello = "Some value";
assign('hello');
Ouputs: Some value
What you wish to do, PHP does not intend for. There is no conventional way to accomplish this. In fact, only quite extravagant solutions are available. One that remains as close to PHP as I can think of is creating a new class.
You could call it NamedVariable, or something, and as its constructor it takes the variable name and the value. You'd initiate it as $products = new NamedVariable('products', $productData); then use it as $this->view->assign($products);. Of course, your declaration line is now quite long, you're involving yet another - and quite obscure - class into your code base, and now the assign method has to know about NamedVariable to extract both the variable name and value.
As most other members have answered, you are better off suffering through this slight lack of syntactic sugar. Mind you, another approach would be to create a script that recognizes instances of assign()'s and rewrites the source code. This would now involve some extra step before you ran your code, though, and for PHP that's silly. You might even configure your IDE to automatically populate the assign()'s. Whatever you choose, PHP natively intends no solution.
This solution uses the GLOBALS variable. To solve scope issues, the variable is passed by reference, and the value modified to be unique.
function get_var_name(&$var, $scope=FALSE) {
if($scope) $vals = $scope;
else $vals = $GLOBALS;
$old = $var;
$var = $new = 'unique'.rand().'value';
$vname = FALSE;
foreach ($vals as $key => $val) {
if($val === $new) $vname = $key;
}
$var = $old;
return $vname;
}
$testvar = "name";
echo get_var_name($testvar); // "testvar"
function testfunction() {
$var_in_function = "variable value";
return get_var_name($var_in_function, get_defined_vars());
}
echo testfunction(); // "var_in_function"
class testclass {
public $testproperty;
public function __constructor() {
$this->testproperty = "property value";
}
}
$testobj = new testclass();
echo get_var_name($testobj->testproperty, $testobj); // "testproperty"