Function inside function not working? [closed] - php

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I tried to make a function inside a function:
<?php
class usermanager extends datamanager {
public $id;
public $name;
public $from;
public $twitter;
public $instagram;
public $skype;
public $regIP;
public $lastIP;
public $email;
public function __construct($exists = false,$uid = 0) {
if ($exists == true) {
$this->id = $uid;
$this->name = $this->fetch("SELECT * FROM users WHERE ID = '".$uid."';")->name;
public function getProfile() {
profile();
}
}
else {
public function new($name,$password,$email) {
$this->autocommit(false);
if (!($do = $this->query("INSERT INTO users (name,password,email,rank) VALUES ('".$name."',PASSWORD('".$password."'),'".$email."','0');"))) {
$this->rollback();
return false;
}
else {
$this->commit();
return true;
}
} //end new()
} //end else
} //end __construct()
public function __set() {
trigger_error("Can not edit read-only variable",E_USER_ERROR);
} //end __set()
private function profile() {
$gets = array("twitter","instagram","skype","from");
$fetch = $this->fetch("SELECT * FROM users WHERE ID = '".$this->id."';");
foreach ($gets as $get) {
$this->$get = $fetch->$get;
}
}
} //end class
?>
Because I saw this I thought it would work, but I got:
Parse error: syntax error, unexpected T_PUBLIC in /home/a7405987/usermanager.php on line 21
Why doesn't this work?
It is fixed now, but now I'm getting another error:
Call to undefined function getProfile()
How can I fix this?

Defining a function within a function isn't a great idea. Aside from classes, any function definitions are automatically global. The public and private keywords are only valid in a class definition, not within a class function. If you were to remove the public from your inner function definition, it would run without error, but the result would be a globally defined getProfile().
This example should help demonstate the issue:
<?php
class Test {
public function foo() {
function bar() {
echo "Hello from bar!" . PHP_EOL;
}
echo "Hello from foo!" . PHP_EOL;
}
}
$t = new Test;
// PHP Fatal error: Call to undefined method Test::bar()
// $t->bar();
// Works, prints "Hello from foo!"
// bar() is now defined, but not where you expect
$t->foo();
// PHP Fatal error: Call to undefined method Test::bar()
// $t->bar();
// Works, prints "Hello from bar!"
// Note that this is global scope, not from Test
bar();
Demo in action

You cannot use modifiers public/private/protected inside a member function or here a constructor. You can however declare a function inside a method :
public function classMember() {
function doSomething() {
//do something
}
doSomething()
}
For your particular problem, you should instanciate your class and then check if it exists, otherwise insert it.
You cannot change the structure of a class depending on the context it is called

Related

How to make __get() called recursively in PHP?

How to let C::update2() could access $this->a by __get()? I'm using PHP 7.
<?php
class C
{
public $data = [];
public function __get($p)
{
if (!array_key_exists($p, $this->data))
$this->fetchData(); // should be a properties to update method mapper
return $this->data[$p] ?? null;
}
public function fetchData()
{
$api_data = ['a'=>'123','b'=>'456'];
$this->data['a'] = $api_data['a'];
if ($api_data['b'] == '456') {
$this->fetch2(); // in this method, it'll call some others API
} else {
$this->fetch3(); // also calls API, but different from update2
}
}
public function fetch2()
{
echo json_encode($this->data)."\n";
echo $this->a;
}
public function fetch3()
{
echo json_encode($this->data)."\n";
echo $this->a;
echo $this->b;
}
}
$c = new C;
echo $c->a;
output
{"a":"123"}
PHP Notice: Undefined property: C::$a in /test.php on line 27
PHP Stack trace:
PHP 1. {main}() /test.php:0
PHP 2. C->__get() /test.php:32
PHP 3. C->fetchData() /test.php:9
PHP 4. C->fetch2() /test.php:18
123
The reason I want to do this is I want to make it resolving the properties lazily and without knowing how the properties comes out(black box).
After seeing Nigel Ren's comment, I gave up on using $this->prop syntax in side the class. I use $this->get('prop') instead.
public function __get($property)
{
return $this->get($property);
}
public function get($property)
{
// resolve the property here
}
// other methods inside class
public function method()
{
$this->method2($this->get('prop_1') + $this->get('prop_2'));
}

PHP Magic __invoke upon object-property of a class

Consider this class arrangement - and in particular the magic function __invoke:
class Barman {
public function __construct() {
// .. .constructor stuff - whatever
}
public function makeDrink() {
return "vodka martini, shaken";
}
}
class Bar {
private $arr_barmen = array();
public function __construct() {
$this->arr_barmen['john'] = new Barman();
}
public function __invoke($barman_id) {
echo "I have been invoked";
return $this->arr_barmen[$barman_id];
}
public function aBarFunc($param) {
return "yes it worked ," .$param;
}
}
class Foo {
public $myBar;
public function __construct() {
$this->myBar = new Bar();
}
}
I want to write syntax like this
$company = new Foo();
$company->myBar('john')->makeDrink();
Preferred result:
"vodka martini, shaken"
Actual result:
"Call to undefined method Foo::myBar()"
Invoking myBar() with the magic method should return a barman Object upon which you can call any of the barman's public methods
But now consider this (which does work)
$company = new Foo();
$myBar = $company->myBar;
$drink = $myBar('john')->makeDrink();
echo $drink;
// Result:
// I have been invoked
// vodka martini, shaken
So what's going on? I don't like that workaround - it's not sleek.
I need it to work this way:
$company->myBar('john')->makeDrink();
Please help? :-)
I believe you can just add braces around it:
$company = new Foo();
$drink = ($company->myBar)('john')->makeDrink();
echo $drink; // vodka martini, shaken
This is being caused by an ambiguity in the call you're trying to make:
$company->myBar('john')->makeDrink();
Because myBar is a property, the PHP interpreter isn't expecting it to be callable. It is parsing it as an attempt to call a method called myBar() which doesn't exist, and is thus throwing the error.
The direct way to resolve this is to clarify the ambiguity for the interpreter. You do this by adding curly braces around the property, as follows:
$company->{myBar}('john')->makeDrink();
The code is now explicit that myBar is a property and should be accessed as such, but that it contains a value that is callable and that you wish to make that call.
This whole topic is complicated (slightly) by the fact that PHP 5.x and PHP 7.x behave differently with regard to how they default to handling these kinds of ambiguity. PHP 7 changed the defaults in order to correct some internal inconsistencies within the language. The result is that in situations like this where you have an ambiguity, if you want your code to work across both PHP 5.x and 7.x, you should always use the braces to explicitly define how you want it to work, regardless of whether your code works for you without them.
There is some documentation about this change in the PHP 7.0 upgrade notes, although the examples given don't cover your exact situation.
To attain chaining you have to return the Barman object in invoke.
class Barman {
public function __construct() {
// .. .constructor stuff - whatever
}
public function makeDrink() {
return "vodka martini, shaken";
}
}
class Bar {
private $arr_barmen = array();
public function __construct() {
$this->arr_barmen['john'] = new Barman();
}
public function __invoke($barman_id) {
echo "I have been invoked";
return $this->arr_barmen[$barman_id] = new Barman();
}
public function aBarFunc($param) {
return "yes it worked ," . $param;
}
}
class Foo {
public $myBar;
public function __construct() {
$this->myBar = new Bar();
}
// create a function with variable name to invoke the object
public function myBar($name) {
$mybar = $this->myBar;
return $mybar($name);
}
}
Thank you for the responses. I devised a cute workaround as follows:
class Barman {
public function __construct() {
}
public function makeDrink() {
return "vodka martini, shaken";
}
}
class Bar {
private $arr_barmen = array();
public function __construct() {
$this->arr_barmen['john'] = new Barman();
}
public function getBarman($barman_id) {
return $this->arr_barmen[$barman_id];
}
public function __invoke($barman_id) {
echo "I have been invoked \n";
return $this->arr_barmen[$barman_id];
}
}
class Foo {
private $_myBar;
public function __construct() {
$this->_myBar = new Bar();
}
// The fix
public function myBar($barman_id) {
return $this->_myBar->getBarman($barman_id);
}
}
Usage:
$company = new Foo();
$drink = $company->myBar('john')->makeDrink();
echo $drink; // vodka martini, shaken
How it works?
Foo->myBar becomes private (Foo->$_myBar);
we create a public function with the name myBar inside Foo;
we create a "getBarman" fuction inside Bar which is called from Foo->myBar('john')
A few more steps - and now there's no ambiguity - Foo->myBar() IS always a function.
Cheers
M

What happens when a PHP object is echoed? [duplicate]

This question already has answers here:
How to echo a custom object in PHP?
(4 answers)
Closed 5 years ago.
If you look at the usage for this library,
https://github.com/Gregwar/Formidable
You have,
$form = new Gregwar\Formidable\Form('forms/example.html');
$form->handle(function() {
echo "Form OK!";
}, function($errors) {
echo "Errors: <br/>";
foreach ($errors as $error) {
echo "$error<br />";
}
});
echo $form;
My question is, how is this done?
How do you echo the $form object..
for eg if I have
class Something
{
public $somevariable = 'London';
public function __construct()
{
$this->foo();
}
public function foo(){
//Do Something
}
}
$myObj = new Something();
echo $myObj;
The above code gives me an error.
What can I do to echo $myObj and not get an error so I can have something displayed on the screen?
We all know we can do something like,
echo $myObj->somevariable;
without an error.. How can I do
echo $myObj;
without getting an error as it is done in the Formidable library.
Magic method __toString() in your class. This allows your class to execute the code in that method when your object is treated like a string (i.e. when used with echo). The method must return a string, otherwise it will raise an error.
You will notice in the library you linked, that they have one in their form class.
/**
* Convert to HTML
*/
public function __toString()
{
return $this->getHtml();
}
You can add __tostring() magic function to your class
class Something
{
public $somevariable = 'London';
public function __construct()
{
$this->foo();
}
public function foo(){
//Do Something
}
public function __tostring(){
return $this->somevariable;
}
}
Calling echo $myObj will print London

Referencing class function variables in php

I've been looking over the PHP variable scope reference page and I can't seem to find a clear answer. I'm working with this basic model where I want to call a class function and have all of its variables accessible outside the class. I want to avoid using the global declaration as well and do this in the most efficient way possible.
class my_class() {
function my_class_function() {
$my_class_function_variable = 'juice';
return $my_class_function_variable;
}
}
$class_instance = new my_class();
function display_juice() {
$class_instance::my_class_function();
$my_class_function_variable;
}
Is there a quick answer in what I'm missing? I'm not getting any output or errors.
EDIT
I'm getting a syntax error when I declare the following within the class but not within the function.
public $current_user = wp_get_current_user();
Parse error: syntax error, unexpected '(', expecting ',' or ';'
You can access all setted variables in class if they are public.
And you can access any of its function if its again public...
Here is example . I have default value 'mydefault'.
I use it, then I change it and again I use it..
class my_class {
public $variable = "mydefault";
public function change_variable($value) {
$this->variable = $value;
}
}
function display_juice() {
$class = new my_class;
echo $class->variable; // echo default value - 'mydefault'
$class->change_variable('newvalue');
echo $class->variable; // echo default value - 'newvalue'
}
display_juice();
Edit..
class my_class {
public $variable;
public function __construct() {
$this->variable = wp_get_current_user();
}
}
You need to make my_class_function() static, the you can call it with my_class::my_class_function()
http://php.net/manual/en/language.oop5.static.php
Also as suggested bellow, you need to return 'juice'.
return 'juice';
You currently don't return anything, you would have to do something like this:
class my_class() {
function my_class_function() {
$my_class_function_variable = 'juice';
return $my_class_function_variable;
}
}
function display_juice() {
$class_instance = new my_class(); //Needs to be inside the function
$my_class_function_variable = $class_instance->my_class_function();
echo $my_class_function_variable;
}
display_juice();
If you want to use a static function or variable you could do this, which eliminates the need for having to create an instance of my_class:
class my_class() {
static function my_class_function() {
return 'juice';
}
}
function display_juice() {
$my_class_function_variable = my_class::my_class_function();
echo $my_class_function_variable;
}
display_juice();
I would make the variable you're trying to access a public member
class my_class {
public $my_class_function_variable = 'juice';
public function my_class_function() {
}
}
$class_instance = new my_class();
function display_juice() {
echo my_class->$my_class_function_variable;
}
display_juice();

Magic Method __set() on a Instantiated Object

Ok i have a problem, sorry if i cant explaint it clear but the code speaks for its self.
i have a class which generates objects from a given class name;
Say we say the class is Modules:
public function name($name)
{
$this->includeModule($name);
try
{
$module = new ReflectionClass($name);
$instance = $module->isInstantiable() ? $module->newInstance() : "Err";
$this->addDelegate($instance);
}
catch(Exception $e)
{
Modules::Name("Logger")->log($e->getMessage());
}
return $this;
}
The AddDelegate Method:
protected function addDelegate($delegate)
{
$this->aDelegates[] = $delegate;
}
The __call Method
public function __call($methodName, $parameters)
{
$delegated = false;
foreach ($this->aDelegates as $delegate)
{
if(class_exists(get_class($delegate)))
{
if(method_exists($delegate,$methodName))
{
$method = new ReflectionMethod(get_class($delegate), $methodName);
$function = array($delegate, $methodName);
return call_user_func_array($function, $parameters);
}
}
}
The __get Method
public function __get($property)
{
foreach($this->aDelegates as $delegate)
{
if ($delegate->$property !== false)
{
return $delegate->$property;
}
}
}
All this works fine expect the function __set
public function __set($property,$value)
{
//print_r($this->aDelegates);
foreach($this->aDelegates as $k=>$delegate)
{
//print_r($k);
//print_r($delegate);
if (property_exists($delegate, $property))
{
$delegate->$property = $value;
}
}
//$this->addDelegate($delegate);
print_r($this->aDelegates);
}
class tester
{
public function __set($name,$value)
{
self::$module->name(self::$name)->__set($name,$value);
}
}
Module::test("logger")->log("test"); // this logs, it works
echo Module::test("logger")->path; //prints /home/bla/test/ this is also correct
But i cant set any value to class log like this
Module::tester("logger")->path ="/home/bla/test/log/";
The path property of class logger is public so its not a problem of protected or private property access.
How can i solve this issue? I hope i could explain my problem clear.
EDIT:
A simple demonstration
Modules::Name("XML_Helper")->xmlVersion ="Hello"; // default is 333
$a = Modules::Name("XML_Helper")->xmlVersion; // now $a should contain "Hello"
echo $a; // prints 333
What i need is
Modules::Name("XML_Helper")->xmlVersion ="Hello"; // default is 333
$a = Modules::Name("XML_Helper")->xmlVersion; // now $a should contain "Hello"
echo $a; // prints Hello
I realise you already said that path is public, but it's still worth mentioning: If you're using PHP 5.3.0+, note this quirk of property_exists():
5.3.0 | This function checks the existence of a property independent of
accessibility
In other words, if you check if (property_exists($delegate, $property)), you have no guarantee you have access to $delegate->$property for writing (or reading, for that matter, but you are trying to write).
As for actual troubleshooting: You could try checking if your if (property_exists($delegate, $property)) statement actually executes. If it doesn't, check the case of $property.
Sidenote: It's fairly hard to read the code you posted up, which makes it a bit of a pain to troubleshoot. Could you edit your post and indent it properly?
The path property of class logger is public so its not a problem of
protected or private property access.
That's your problem. From the docs:
__set() is run when writing data to inaccessible properties.
That suggests that __set() is not called for public properties.

Categories