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.
Related
Configuration of a project in dev mode with WAMP.
PHP vers 5 and 7 are available.
Just trying to set the project root using filter_input. Could someone please explain why filter input for the protected and private vars inside the class reports a PARSE ERROR? However if used outside the class or inside a function of the class it works.
Is there a better way to do this so that it can be used globally? I find this is called a lot and would prefer to do it once.
$test = filter_input(INPUT_SERVER,'DOCUMENT_ROOT');
echo $test; //good
class FooBar{
protected $_test = filter_input(INPUT_SERVER,'DOCUMENT_ROOT'); //bad - Parse error: syntax error, unexpected '(', expecting ',' or ';'
private $_test2 = filter_input(INPUT_SERVER,'DOCUMENT_ROOT'); //bad - Parse error: syntax error, unexpected '(', expecting ',' or ';'
function __construct() {
}
public function getProducts(){
include_once
(filter_input(INPUT_SERVER,'DOCUMENT_ROOT').'/obj/user.php'); //good
}
}
You can not directly assign a function return value to a property in the class definition.
This is because the function could return different return values, and the class is only a blueprint which you must instantiate as an object to use.
For the objects that are created from your class definition you can initialize any property in the constructor:
class FooBar {
protected $var = null;
private $var2 = null;
function __construct() {
$this->var = func1();
$this->var2 = func2();
}
}
// no parse error
Despite of that, why do you use filter_input on an internal constant? You only need to filter input from the outside, i.e. GET/POST/SESSION content (user input), input read from files, from external APIs etc. But you don't need to use that on internal constants like the DOCUMENT_ROOT:
class FooBar {
private $_docroot = $_SERVER['DOCUMENT_ROOT'];
}
// no parse error
I have a strange behavior in my php 5.3
i have a class wich dous this in a function
$new = new self($data);
$new->setServiceManager($this->service);
$new->cacheInstance();
BUT the function cacheInstance is a private function....
private function cacheInstance()
{
foreach ($this->data as $name => $class) {...}
}
Can some one give an explanation why the hell can this be used like this? shouldn`t this method be private aka unaccessible from outside?
UPDATE:
ok now im totally lost... i can even acess the private variables of the instance... like what the ... this has to be some intended behavior, can somone point me in a direction?
If you can create a class instance with new self() it means you are in the class, and of course you can access private properties an functions. This snippet is taken from the PHP Docs (link)
/**
* Define MyClass
*/
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello(); // Shows Public, Protected and Private
IN YOUR CASE:
class Cache {
private $service = null;
private function cacheInstance()
{
foreach ($this->data as $name => $class) {}
}
public function setServiceManager( $service ) {
}
public function myTest( $data ) {
$new = new self( $data );// you are in the class, so you can call new self()
$new->setServiceManager($this->service);
$new->cacheInstance();
}
}
$cache = new Cache();
$cache->service; //Fatal error: Cannot access private property
$data = array();
$cache->myTest( $data );// working
$cache->cacheInstance();// not working
private, protected and public accessibility works on class level, not on object level.
While it may seem counter intuitive first, this is not your usual PHP weirdness.
It's the same in other OOP languages, like Java
Note that accessibility is a static property that can be determined at compile time; it depends only on types and declaration modifiers.
and C#
The private keyword is a member access modifier. Private access is the least permissive access level. Private members are accessible only within the body of the class or the struct in which they are declared
(highlights added)
Explanation
The accessibility is a mechanism to hide implementation details from code in other classes, not for encapsulation of objects. Or as it's stated in the Java specs, accessibility can be determined at compile time, i.e. there cannot be a runtime violation because it's a different object.
It makes sense, if you look at the difference between private and protected. For private members, an object does not have access to its own members if they are declared in a parent class. Sounds weird? That's because the terminology is wrong. The class does not have access to privates of its parent class (i.e. it may not use them).
Now in your method, you use private variables within the same class. There is no need to hide this implementation detail from yourself, the author of this class, no matter what the objects are at runtime.
ok... wierd like quantum mechanics... have been pointed in RL to the answer
http://php.net/manual/en/language.oop5.visibility.php
QUOTE:
Objects of the same type will have access to each others private and
protected members even though they are not the same instances. This is
because the implementation specific details are already known when
inside those objects.
Talking about wierd...
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.
Here's my test:
<?php
require __DIR__ . '/vendor/autoload.php';
class HasStatic {
public static function static_method() {
return true;
}
}
class SUT {
public $has_static;
public function __construct() {
$this->has_static = new HasStatic();
}
public function call_static() {
// A parse error :<
// $this->has_static::static_method();
$has_static = $this->has_static;
return $has_static::static_method();
}
}
class PhpStaticCallOnProperty extends PHPUnit_Framework_TestCase {
public function testPhpStaticCallOnProperty() {
$sut = new SUT();
$this->assertTrue($sut->call_static(), 'call_static() succeeded');
}
}
As you can see, I discovered that $this->has_static::static_method(); yields a parse error.
Is there a clean way to make this call without the extra assignment?
Static methods are black boxes of functionality where you explicitly define everything going in (parameters) and out (return value). As such, they are not tied to an object - and you shouldn't call them using an object reference. static_method() should only ever be called using HasStatic::static_method(), or self::static_method() from within the HasStatic class.
There's nothing inherently wrong with static methods - I strongly disagree with tereško saying they should be avoided. If a method doesn't need an object's context, it may as well be static.
The parse error occurs because there's no reason to use the scope resolution operator (::) on a property. Variable class names do mean the following will work:
$foo = 'HasStatic';
$foo::static_method(); // equivalent to HasStatic::static_method()
However that variable cannot be a property - you'll have to assign it to a temporary variable if you want to call the method in this way.
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.