how to define a constant member of a class with $_SERVER superglobals? - php

I have this code
class View
{
const DEFAULT_VIEWS_DIRECTORY = $_SERVER["DOCUMENT_ROOT"] . "views/";
}
but, it gives me syntax error
Parse error: Parse error: syntax error, unexpected '$_SERVER' (T_VARIABLE) in C:\xampp\htdocs\classes\View.class.php on line 17
I checked the manual and it says
The value must be a constant expression, not (for example) a variable, a property, or a function call.
is there any work around to do what I want ?, because I consume this value in the class heavily, and having this as a constant will make the class more pretty

As you noticed, Expression is not allowed as class constant value, but it doesn't stop you to initiate your default view directory once and and use it on different occasion:
class View
{
private $defaultViewDirectory;
public function __construct()
{
$this->defaultViewDirectory = $_SERVER["DOCUMENT_ROOT"] . "views/";
}
public function getDefaultViewDirectory()
{
return $this->defaultViewDirectory;
}
}
Or you could implement a Singleton pattern like:
class View
{
private $defaultViewDirectory;
private function initDefaultViewDirectory()
{
$this->defaultViewDirectory = $_SERVER["DOCUMENT_ROOT"] . "views/";
}
public function getDefaultViewDirectory()
{
if (is_null($this->defaultViewDirectory)) {
$this->initDefaultViewDirectory();
}
return $this->defaultViewDirectory;
}
}
Or if you need a static access:
class StaticView
{
private static $defaultViewDirectory;
private static function initDefaultViewDirectory()
{
self::$defaultViewDirectory = $_SERVER["DOCUMENT_ROOT"] . "views/";
}
public static function getDefaultViewDirectory()
{
if (is_null(self::$defaultViewDirectory)) {
self::initDefaultViewDirectory();
}
return self::$defaultViewDirectory;
}
}
So you could call StaticView::getDefaultViewDirectory()

Related

php filter_input parse error inside class

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

Inline interface implementation - Implement interface methods at declaration

I come from java, where we can do something like this:
Action.java:
public interface Action {
public void performAction();
}
MainClass.java:
public class MainClass {
public static void main(String[] args) { //program entry point
Action action = new Action() {
public void performAction() {
// custom implementation of the performAction method
}
};
action.performAction(); //will execute the implemented method
}
}
As you can see, I'm not creating a class which implements Action, but I'm implementing the interface directly on declaration.
Is something like this even possible with PHP?
What I've tried:
action.php:
<?php
interface Action {
public function performAction();
}
?>
myactions.php:
include "action.php";
$action = new Action() {
public function performAction() {
//do some stuff
}
};
What I get:
Parse error: syntax error, unexpected '{' in myactions.php on line 3
So, my question is: is something like this possible with PHP? How should I do it?
With PHP 7, this has become possible with anonymous classes.
$action = new class implements Action() {
public function performAction() {
//do some stuff
}
};
No, can't. PHP doesn't offer anonymous classes like Java does. You can however try to simulate the behaviour you want, but the results will be...mixed at best.
Here's some code:
interface Action
{
public function performAction();
}
class MyClass
{
public function methodOne($object)
{
$object->performAction(); // can't call directly - fatal error
// work around
$closure = $object->performAction;
$closure();
}
public function methodTwo(Action $object)
{
$object->performAction();
}
}
$action = new stdClass();
$action->performAction = function() {
echo 'Hello';
};
$test = new MyClass();
$test->methodOne($action); // will work
$test->methodTwo($action); // fatal error - parameter fails type hinting
var_dump(method_exists($action, 'performAction')); // false
var_dump(is_callable(array($action, 'performAction'))); // false
Hope it helps!

How to assign function's output array to a variable in PHP?

Below is my simplified code where it's giving me errors. It's probably a very simple thing but it's making me confused.
class MyController extends ParentController {
public $pet_list = $this->pet_list_array();
//Parse error: syntax error, unexpected T_VARIABLE in ......
public function pet_list_array() {
return array('cat'=>'Steve\'s Cat',
'dog'=>'Fiona\'s Dog',
'lion'=>'John\'s Lion');
}
}
If I do this instead, I get a different error
public $pet_list = pet_list_array();
//Parse error: syntax error, unexpected '(', expecting ',' or ';' in.....
But if I do this public $pet_list = pet_list_array; (without the round brackets after the function name), it seems to work fine. Is this a normal behaviour? I am a bit unsure.
Your problem is that you can't make a call to a class method in the class definition. Make a __construct() method and set it there, like so:
class MyController extends ParentController {
public $pet_list;
public function __construct(){
$this->pet_list = $this->pet_list_array();
}
public function pet_list_array() {
return array('cat'=>'Steve\'s Cat',
'dog'=>'Fiona\'s Dog',
'lion'=>'John\'s Lion');
}
}
Of course, you probably don't need both $pet_list and pet_list_array() in the same class if they return the same value all the time.

Return reference to static variable from __callStatic?

I'm trying to find a workaround for static variables not being copied over to extending classes (which doesn't play nicely with late static binding), here is what I thought might work, but gives me a "PHP Fatal error: Can't use function return value in write context" :
<?php
class Person
{
protected static $tlsb_names = ['name'];
protected static $tlsb_vars = [];
public static function & __callStatic($method,$args)
{
echo "call static " . $method . " on " . get_called_class() . "\n";
if(in_array($method,static::$tlsb_names))
{
if(!array_key_exists(get_called_class(),static::$tlsb_vars))
{
static::$tlsb_vars[get_called_class()] = [];
}
if(!array_key_exists($method, static::$tlsb_vars[get_called_class()]))
{
echo "set var $method for " . get_called_class() . "\n";
static::$tlsb_vars[get_called_class()] = null;
}
return static::$tlsb_vars[get_called_class()][$method];
}
}
public static function show_name()
{
static::name() . "\n";
}
public static function call_me_al()
{
static::name() = "Al";
}
public static function call_me_joe()
{
static::name() = "Joe";
}
}
class Al extends Person{}
class Joe extends Person{}
Al::call_me_al();
Joe::call_me_joe();
Al::show_name();
Joe::show_name();
The problematic part is with the lines :
public static function call_me_al()
{
static::name() = "Al";
}
Apparently this is a compile-time error since non of my echo's are run.
What am I doing wrong here?
The following line of code is wrong:
public static function & __callStatic($method,$args)
You need to match the definition of that __callStatic functionDocs and that is without return by reference:
public static function __callStatic($name, $arguments)
So what you try to achieve is not possible.
And the other problem you circle around with should be able to solve with late static binding (LSB)Docs.
Also keep in mind that Magic is hard to debug, so get your step-debugger ready and step through the application so you can better understand what is actually happen. The debugger in PHP is called Xdebug, most PHP IDEs and editors support it.

Another "Yet another call to a member function function() on a non-object"

How come a simple instantiation doesn't work? I have been doing the same method to all of the classes I created/instantiated but this is the only one that's giving me this kind of error.
Fatal error: Call to a member function validate_fname_and_lname() on a non-object in /homepages/......../Validate.php on line 23
Here's my code:
//Class Validate
<?php
require_once 'RegExp.php';
$myRegExp = new RegExp();
class Validate
{
//Sends each entry to corresponding RegExp function with appropriate regular expression
function validate_form($un, $fname)
{
$err_counter = 0;
if(!$this->myRegExp->validate_fname_and_lname($fname))
{
$error_identifier .= 'firstName+';
++$err_counter;
}
}
}
//Class RegExp
<?php
class RegExp
{
function validate_fname_and_lname($flname)
{
return preg_match("/[a-zA-Z' ']{2,}/", $flname);
}
}
I think you are trying to access the global $myRegExp from within object scope.
You should probaby add a constructor to your validator:
public function __construct($re)
{
$this->myRegExp = $re;
}
And then instantiate your Validator like this:
$validator = new Validate($myRegExp);
And you should declare a member variable 'myRegExp' in your Validate class.
And on a side note: I think you should rethink your design. If I were you I'd create an interface:
interface IValidator
{
public function valid($input);
}
Let your specific regex classes implement that interface:
class ValidateFnameAndLname implements IValidator
{
function valid($flname)
{
return preg_match("/[a-zA-Z' ']{2,}/", $flname);
}
}
And construct your Validate class like this:
class Validate
{
protected $myRegExp;
public function __construct(IValidator $validator)
{
$this->myRegExp = $validator;
}
//Sends each entry to corresponding RegExp function with appropriate regular expression
function validate_form($un, $fname)
{
$err_counter = 0;
if(!$this->myRegExp->valid($fname))
{
$error_identifier .= 'firstName+';
++$err_counter;
}
}
}
Then you are on your way to get a more coherent design.
I'm guessing this is the line giving you a problem?
if(!$this->myRegExp->validate_fname_and_lname($fname))
You use $this->myRegExp, but thats not a member of the Validate class. You have $myRegExp declared as a global variable.

Categories