So, the question pretty much explains what i want. Here is the minimum code of what i am doing.
class AuthorizeController extends Controller
{
private $aNetEnvironment;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->aNetEnvironment = env('ANetEnvironment');
}
public function setEnvironment()
{
$controller = new AnetController\GetCustomerProfileController($request);
// $this->aNetEnvironment = SANDBOX
$response = $controller->executeWithApiResponse(
\net\authorize\api\constants\ANetEnvironment::$this->aNetEnvironment
);
}
}
Searching stackoverflow i got two options, have tried both with no luck.
Trying, {$this->aNetEnvironment} gives
syntax error, unexpected ')', expecting '('
Trying, $$this->aNetEnvironment gives
Object of class App\Http\Controllers\AuthorizeController could not be
converted to string
Edit:
Trying, ${$this->aNetEnvironment} gives
Access to undeclared static property:
net\authorize\api\constants\ANetEnvironment::$SANDBOX
Is there any other option ?
You could make use of the PHP's constant() helper. From the docs:
Signature:
constant ( string $name ) : mixed
Return the value of the constant indicated by name.
constant() is useful if you need to retrieve the value of a
constant, but do not know its name. I.e. it is stored in a variable or
returned by a function.
This function works also with class constants.
So in your case:
$response = $controller->executeWithApiResponse(
constant('\net\authorize\api\constants\ANetEnvironment::' . $this->aNetEnvironment)
);
To use class properties as variable variables in this way you need to start with a $ and wrap the property in {} e.g. ${$this->property} so you should be able to use the following in your controller:
\net\authorize\api\constants\ANetEnvironment::${$this->aNetEnvironment}
Related
PHP 7 added support for anonymous classes, however I can't seem to find any information regarding associated scoping issues. I know I can use the use keyword with callables/closures to access outer scoped variables (like function() use ($outer) { // do work with $outer }), is there any way to do that with an anonymous class?
I would like to be able to do so without relying on the anonymous class constructor arguments, and without doing things like adding a setter method or public property to store the value after the instantiation.
Here's an example:
$outer = 'something';
$instance = new class {
public function testing() {
var_dump($outer); // would like this to dump the string 'something'
}
};
another solution could be
$outer = 'something';
$instance = new class($outer) {
private $outer;
public function __construct($outer) {
$this->outer = $outer
}
public function testing() {
var_dump($this->outer);
}
};
The unique way to access outside variable in this case is use $ _GLOBAL (I don't recommend). If you do not want to use constructor or setter method, my suggestion is to use a STATIC variable inside the anonymous class and set the value after the attribuition to the variable that contains the instance of anonymous class (Its not possible to define the static value before, because the class is anonymous..). Doing this, you have a better control and a static variable, but in certain way this is not very usual, every time when you create a new anonymous class the instance and it values belongs to the VARIABLE that receives the "new object", maybe is better for you to create a real class.. But follow a example with a static value and a anonymous class:
$i = new class {
public static $foo;
};
var_dump($i::$foo); //No value
$i::$foo = "Some value";
var_dump($i::$foo); //Has value
http://php.net/manual/en/language.variables.scope.php
There are some instructions in the php variable scope documentation.
This script will not produce any output because the echo statement refers to a local version of the $a variable, and it has not been assigned a value within this scope. You may notice that this is a little bit different from the C language in that global variables in C are automatically available to functions unless specifically overridden by a local definition. This can cause some problems in that people may inadvertently change a global variable. In PHP global variables must be declared global inside a function if they are going to be used in that function.
In php, the scope that a method inside a class can access is restricted to the inside of the entire class and cannot be accessed up to other scopes. So I think that the effect you want is not implemented in php, at least until the PHP GROUP decides to change the default behavior of PHP.
Of course, you can still use it by declaring variables as global.
Even though the OP did state that they would like to avoid public properties and anonymous class constructor arguments, the accepted answer is exactly that, so here is an example using a public property, which can be improved with a private property and a setter to maintain encapsulation:
class Foo {
public function executionMethod() {
return "Internal Logic";
}
}
$foo = new Foo();
var_dump("Foo's execution method returns: " . $foo->executionMethod());
$bar = new class extends Foo {
public $barVal;
public function executionMethod() {
return $this->barVal;
}
};
$bar->barVal = "External Logic";
var_dump("Bar's execution method returns: " . $bar->executionMethod());
I find this useful if you are unable to override the inherited class's constructor.
This will output:
string(46) "Foo's execution method returns: Internal Logic"
string(46) "Bar's execution method returns: External Logic"
If you want your anonymous class to have access to outer properties and methods that are protected or private, you could take advantage of the fact that closures inherit the scope they're defined in, and tie them into some magic methods for seamless behavior.
This is untested, but I'm pretty sure it'd work:
$class = new class {
/**
* #var \Closure
*/
public static $outerScopeCall;
/**
* #var \Closure
*/
public static $outerScopeGet;
/**
* #param string $name
* #param array $arguments
* #return mixed
*/
public function __call(string $name, array $arguments = [])
{
$closure = static::$outerScopeCall;
return $closure($name, $arguments);
}
/**
* #param string $name
* #param array $arguments
* #return mixed
*/
public function __get(string $name)
{
$closure = static::$outerScopeGet;
return $closure($name);
}
};
$class::$outerScopeCall = function (string $name, array $arguments = []) {
return $this->$name(...$arguments);
};
$class::$outerScopeGet = function (string $name) {
return $this->$name;
};
The $call closure will have access to the definition of $this from where it's defined as opposed to where
I just start learning PHP few days ago so forgive me if this question is a newbie one.
What is wrong with my declaration of CRAWLER_URI ? The env() isn't working outside a method and I don't know why.
namespace App\Http\Controllers;
use GuzzleHttp\Client;
class SpotifyController extends Controller
{
const CRAWLER_URI = env('CRAWLER_URI') . ':' . env('CRAWLER_PORT');
/**
* Send a GET to Crawler API
* #return a json crawled by an external API crawler
*/
public function fetch()
{
$client = new Client(['base_uri' => self::CRAWLER_URI]);
$response = $client->request('GET');
dd($response);
}
}
So, the issue here is that you can’t use a function as a class constant value:
According to the PHP manual:
The value must be a constant expression, not (for example) a variable, a property, or a function call.
There are many solutions to this problem, for example, if you really want it to be constant, you could use a define() statement like this:
define('CRAWLER_URI', env('CRAWLER_URI') . ':' . env('CRAWLER_PORT'));
and access it like this:
echo CRAWLER_URI;
Another method would be to use a static function:
private static function CRAWLER_URI() {
return env('CRAWLER_URI') . ':' . env('CRAWLER_PORT');
}
and access it like this:
echo $this->CRAWLER_URI();
I have following code
class DataMapperFactoryBeta
{
static private $configClassName = 'ConfigBeta';
static private $client;
static private $mapper = [];
static public function initClient()
{
$className = 'Models\\DataMappers\\Clients\\'.self::$configClassName::$db_type;
}
}
The Interpretor throws me a fatal error: 'incorrect access to static class member'. I wish to have the config class name accessed dynamicly, because I will change it in the future and I don't wanna change it in many places in the code, only once, through $configClassName. Is this even possible with statics?
Split your line into two, and it should work for you as you expect:
$className = 'Models\\DataMappers\\Clients\\' . self::$configClassName;
$className = $className::$db_type;
On a side note, I couldn't find in the PHP docs whether the scope resolution operator (::) is left or right associative. It could be it's trying to interpret the line as follows:
('Models\\DataMappers\\Clients\\'.self::($configClassName::$db_type));
Without an update from the docs the code is ambiguous as to what exactly should be happening the way you have it written.
I wanted to have a static closure variable in my class, so that people can change the behavior of a specific part of the code. However, I can't seem to be able to initialize it anywhere.
First I tried this:
public static $logger = function($sql) { print_r($sql); };
But apparently PHP can't handle that. Ok, so I made a static init method:
public static $logger;
static function init() {
/* if (!Base::logger) */
Base::logger = function($sql) { print_r($sql); };
}
And call it at the end of the file, outside class definition. But this also give me a syntax error: Parse error: syntax error, unexpected '=' in [file] on line [line]. Any hints?
The syntax error is right where the error message tells you it is (it would have been even easier to spot if you had given us line numbers...): a missing $-sign.
Base::$logger = function (...)
In addition to that, you migth want to use self:: instead of Base::, this ensure the code will work without any additional changes if you ever rename the class
self::$logger = function (...)
You can improve this code even further, when changing the initializer to a getter that JIT-creates the closure:
private static $logger = NULL;
public static function getLogger () {
if (self::$logger === NULL) {
self::$logger = function ($sql) {print_r($sql);};
}
return self::$logger;
}
[Edit] Based on your comment on this: the clean OOP way of being able to change $logger would be to use a setter:
public static function setLogger ($closure) {
self::$logger = $closure;
}
COmbining this and the getter from above ensures that you always get the value set by the setter, and, if none has been set yet, the default value. Using the setter to set the value back to NULL makes the getter create the default again, which is anoth er plus.
Lets say in the very first script, which always executes first, I defined something:
define ('ROOTDIR', dirname(__FILE__));
define ('ROOTDIR_ASSETS', ROOTDIR.'/assets');
now a class:
class PictureGallery
{
const PATH = ROOTDIR.'/imgs';
php say: syntax error, unexpected '.' expecting ' ' or ';'.
How to work it around?
you can't have a class constant defined with string concatenation.
You'll need to use a member variable. If you don't want this changed, I would suggest making it private and only creating a getter to access it.
class PictureGallery
{
private $_path;
public function __construct()
{
$this->_path = ROOTDIR.'/imgs';
}
public function getPath()
{
return $this->_path;
}
}
OR
You could also calculate the value before defining the class, however this is a messy solution.
define('IMGDIR', ROOTDIR.'/imgs');
class PictureGallery
{
const PATH = IMGDIR;
...
}
Class constants is PHP must be a constant expression. So you either have to create another defined constant with the full path or you have to inject the path into the constructor of the class. Or just set in in the constructor.