Access Level to certain class must be public error in PHP - php

I created this class
<?php
abstract class Validator{
public $_errors = array();
abstract public function isValid($input);
public function _addErrors($message){
$this->_errors = $message;
}
public function getErrors(){
return $this->_errors;
}
public function getMessage(){
return $this->message;
}
}
class Validator_NoSpaces extends Validator{
public function __construct($value){
$this->isValid($value);
}
public function isValid($value){
if (preg_match('/\s/', $value)){
$this->_addErrors("Spaces are not allowed");
return false;
}
return true;
}
}
class Validator_MinimumLength extends Validator{
protected $_minLength;
protected $value;
public function __construct($value ,$minLength=8){
$this->_minLength = $minLength;
$this->value = $value;
$this->isValid($value);
}
public function isValid($input){
if (strlen($input) > $this->_minLength) {
return true;
}else{
$this->_addErrors("Input must be at least {$this_minLength}");
return false;
}
}
}
class Form_Element_Validators extends Validator{
protected $_validators = array();
public function addValidator(Validator $validator)
{
$this->_validators[] = $validator;
}
public function getValidators()
{
return $this->_validators;
}
protected function _addErrors(array $errors)
{
foreach ($errors as $error) {
$this->_addErrors($error);
}
}
public function hasErrors()
{
return (count($this->getErrors()) !== 0);
}
public function isValid($input)
{
foreach ($this->_validators as $validator) {
if (!$validator->isValid($input)) {
$this->_addErrors($validator->getErrors());
}
}
return !$this->hasErrors();
}
}
class Form_Element extends Form_Element_Validators{
public function __construct($value){
$this->addValidator(new Validator_NoSpaces($value));
$this->addValidator(new Validator_MinimumLength($value));
}
}
for Validation purposes, but it kept giving me this error
Fatal error: Access level to Form_Element_Validators::_addErrors() must be public (as in class Validator) in C:\xampp\htdocs\beatbeast\includes\Db\Validators.php on line 91
But the instance variable in this class $_errors is declared public, I don't get it why I am receiving this error.

Youre getting that error because the visibility of the method must be the same or less restrictive than that of it its definition on a parent class. In this case you have addErrors as public on your abstract class and are attempting to make it protected on a child class.

As others have mentioned, you can't make a sub class method more restrictive than the parent; this is because sub classes are supposed to be a valid replacement for their parent class.
In your particular case, I would change the visibility of all methods and properties that start with an underscore to protected.

You've specify the protected access to the protected function _addErrors(array $errors) method of Form_Element_Validators class. So change it to public.
Edit:
Have you noticed? The sub class method (overridden method) is defined with Type Hinting. Please keep the same parameter type for both; super-class and sub-class method.
abstract class Validator{
public $_errors = array();
abstract public function isValid($input);
public function _addErrors(array $message){
$this->_errors = $message;
}
....

Since PHP 7.2.0 there was a bug #61970 fixed (Restraining __construct() access level in subclass gives a fatal error).
Bump your PHP version to 7.2 and you could make it private or protected.

It also happens when you are trying to do something with specific guard.
You can add
protected $guard = "guard_name";
Add above line in your model.
that will solve the problem.

Related

PHP inheritance of abstract classes and overloading

Say I have the following code, is there a way to somehow extend an abstract class on a child and require a different type of argument in the "overloaded" function. I want to insert various types of objects in the Collection through the add function. In some cases, I'd like to insert an Error object, sometimes some other (XYZ) object, and let's say that all those objects extend the same abstract class called Parent.
I would appreciate if somebody could tell me if something like this is even possible, and if it is suggest some ways to accomplish this. Note that production server on which I intend to host the application runs on php 5.6.40.
Thank you in advance.
namespace App;
use App\Models\Parent;
abstract class Collection
{
protected $collection;
public function __construct()
{
$this->collection = array();
}
abstract public function add($key, Parent $item);
}
public class ErrorList extends Collection
{
public function __construct()
{
parent::__construct();
}
public function add($key, Error $item)
{
$this->collection[$key] = $item;
}
}
namespace App\Models;
abstract class Parent {}
public class Error extends Parent {}
public class XYZ extends Parent{}
Try this
abstract class Collection
{
protected $collection;
public function __construct()
{
$this->collection = array();
}
//no type hinting
abstract public function add($key, $item);
}
class ErrorList extends Collection
{
// this constructor doing nothing , it can be removed and
// parent constructor will still be called unlike java or any other
// OOP
public function __construct()
{
parent::__construct();
}
//no type hinting
public function add($key, $item)
{
//code
}
}
If you're extending a class or implementing an interface the signature must match. You can however implement type checking yourself and type hint in a docblock.
As a side note, public class is invalid syntax.
abstract class Collection
{
protected $collection;
public function __construct()
{
$this->collection = array();
}
abstract public function add($key, Parent $item);
}
class ErrorList extends Collection
{
public function __construct()
{
parent::__construct();
}
/**
* #param $key
* #param Parent|Error $item
*/
public function add($key, Parent $item)
{
if (!($item instanceof Error)) {
throw new \InvalidArgumentException('Unable to add object to error list: ' . get_class($item));
}
$this->collection[$key] = $item;
}
}

Can't access construct variable in method ( php laravel )

I have a base class which sets up's other extending controllers like this:
class BaseController extends Controller
{
public $globalCurrencies;
public $globalLanguages;
public function __construct()
{
$this->globalCurrencies = $this->getCurrencies(); // this works
$this->globalLanguages = $this->getLanguages(); // this works
}
}
And I use one of helpers to extend this class like this:
class SessionHelper extends BaseController
{
public $test;
public function __construct()
{
parent::__construct(); // fire parent aka basecontroller construct
$this->test = $this->globalCurrencies; // this works (variables are set)
echo '__construct: '.$this->test; // this even displays it
}
public function getCurrencies()
{
dd('method'.$this->test); // NOT WORKING
}
public function getCurrentCurrency()
{
return $this->getCurrencies()->where('id', Session::get('currencyId'))->first() ?? null;
}
}
Later on code is used in model:
class Product extends Model
{
protected $table = "products";
public $timestamps = true;
public $sessionHelper;
public function __construct()
{
$this->sessionHelper = new SessionHelper;
}
public function getPrice($conversion_rate = null)
{
return number_format($this->price_retail / $this->sessionHelper->getCurrentCurrency()->conversion_rate, 2);
}
}
Have any body idea why I can access in construct variable but not in method? If i remember correctly construct is fired first so everything after should have access to it.
Declare $test variable as private out side the constructor. Inside the constructor keep it the way you are doing it right now and then make a setter and getter for the test variable.
class testObject
{
private $test;
function __construct($test)
{
$this->test= $this->globalCurrencies;
}
// test getter
function getTest()
{
return $this->test;
}
}
Change your method to be;
public function getCurrencies()
{
dd('method', $this->test);
}
You can not concatenate strings and objects/arrays.
If that doesn't resolve the issue - check the laravel.log

overloading conditionally in php

Might be I am missing something obvious.
I have a native class with set and get method.
class DBStorage extends NativeClass{
public function get($key);
public function set($key,value);
}
I would like to use that most of the time, but, if I turn on the system DEBUG flag.
I would like the set and get methods to be overloaded with the following:
IF DEBUG IS ON{
class DBStorage extends NativeClass{
public function get($key){
var_dump($key);
parent::get($key);
}
public function set($key,$value){
var_dump($key,$value);
parent::set($key,$value);
}
}
}
NativeClass is written in C. It is an extension (phpredis, but it is not relevant).
How would I accomplish this?
I am on the 5.3 branch of PHP.
just to make sure...if debug is off, DBStorage will be:
class DBStorage extends NativeClass{}
if debug is on, it will be:
class DBStorage extends NativeClass{
public function get($key){
var_dump($key);
parent::get($key);
}
public function set($key,$value){
var_dump($key,$value);
parent::set($key,$value);
}
}
I do try to avoid the cluttring of IFs (there are dozens of functions in the real class)
public function get($key) {
if (DEBUG) {
var_dump($key);
}
return parent::get($key);
}
You can't conditionally overload, but you can conditionally do something in the overloaded method:
class DBStorage extends NativeClass{
public function get($key) {
if (DEBUG) {
var_dump($key);
}
return parent::get($key);
}
}
If debug is off, it passes the arguments right through to the parent method and returns the parent's return value, as if nothing happened.
Your initial code won't compile, because of the if around the class construct. Why not just make available a debug member variable, and if true, echo output, or push into a log file?
class NativeClass
{
public $debug = false;
}
class DBStorage extends NativeClass
{
public function get($key)
{
if (true === $this->debug) {
error_log(sprintf('Key: %s', $key));
}
parent::get($key);
}
}
// Calling code
$dbo = new DBStorage();
$dbo->debug = true;
$dbo->doStuff();
something just came to me
class nodebug extends NativeClass{
static public function create(){
if(DEBUG) return new DebugNativeClass;
return new self;
}
}
class DebugNativeClass extends nodebug{
public function set($key,$value){
var_dump($key,$value);
parent::set($key,$value);
}
public function get($key){
var_dump($key);
return parent::set($key);
}
}

php Abstracted static variables persist between static method calls

I have a php abstract generic class with several static variables and functions.
class Generic{
public static $ID;
private static $tableName;
private static $oldTableName;
protected static $DAL;
public static function Init($tableName, $id=null) {
if(self::$tableName)
self::$oldTableName=self::$tableName;
self::$tableName=$tableName;
self::$DAL = new DAL(self::$tableName);
}
public static function RecallTableName(){
if(self::$oldTableName){
self::$tableName=self::$oldTableName;
self::$oldTableName=null;
return true;
}
}
public static function GetProperty($id, $columnName, $whereStatement = "1=1"){
if(!self::$tableName)
return false;
//DO DB STUFF HERE
return; //RETURN WHAT DB CALLS DID HERE
}
}
Several classes inherit from this generic class using extends.
class Part extends Generic {
static function Init($tableName="part",$id = null) {
$return = parent::Init($tableName,$id);
new Part();
return $return;
}
public static function destruct(){
parent::RecallTableName();
}
public function __destruct() {
Part::destruct();
}
public static function GetProperty($id, $columnName, $whereStatement = "1=1") {
self::Init();
return parent::GetProperty($id, $columnName, $whereStatement);
}
}
class System extends Generic {
static function Init($tableName="system",$id = null) {
$return = parent::Init($tableName,$id);
new System();
return $return;
}
public static function destruct(){
parent::RecallTableName();
}
public function __destruct() {
Part::destruct();
}
public static function GetProperty($id, $columnName, $whereStatement = "1=1") {
self::Init();
return parent::GetProperty($id, $columnName, $whereStatement);
}
public static function GetInventory($PartManageIDToCheck)
{
return Part::GetInventory($PartManageIDToCheck);
}
}
This way when I implement a method call on a child I can hook on the child's death. Going further, I can call:
System::GetInventory(1)
This will:
1 - Call Init() on Generic which stores "system" in the Generic::$tableName.
2 - Cenerate a nested sibling (Part) which in turn calls Init() on Generic which then moves Generic::$tableNameto Generic::$oldTableNameand stores "part in Generic::$tableName
This all works without issue. However, when I use two children back to back it falls apart.
System::GetProperty(1, "ID");
Part::GetProperty(3, "ID");
Using the two back to back allows Generic to persist somehow so that Generic::$tableName == "system" when Part::GetProperty(3, "ID"); gets called.
Any idea how to fix this?
What you're looking for is late static binding which was added in PHP 5.3. Change the definition of $tableName to protected static $tableName. Then redeclare it exactly the same way in each child class.

singleton in abstract class php

I have a simple question. I use a singleton which implements an abstract class. Is it possible to put the getInstance() Method and the variable $_instance in the abstract class instead of the concrete one I want to create?
Here's my code:
<?php
class Command_Log extends Command_Abstract {
private static $_instance=null;
public static function getInstance() {
if (self::$_instance==null)
self::$_instance=new self();
return self::$_instance;
}
protected function realExecute() {
}
protected function realSimulate($fileHandle) {
}
}
and
<?php
abstract class Command_Abstract implements Command_Interface {
protected $_data=array();
//private static $_instance=null;
protected $_isExecuted=false;
protected $_execute=false;
public function enableExecute() {
$this->_execute=true;
return $this;
}
protected function __construct() {
}
protected function __clone() {}
public function addData($data) {
array_push($this->_data,$data);
return $this;
}
abstract protected function realExecute();
abstract protected function realSimulate($fileHandle);
public function execute() {
if(!$this->_isExecuted && $this->_execute) {
$this->_isExecuted = true;
$this->realExecute();
}
}
public function simulate() {
$exitSystem = false;
if(!$this->_isExecuted && $this->_execute) {
$this->_isExecuted = true;
$exitSystem = $this->realSimulate($fh);
}
}
return $exitSystem;
}
}
I have many implementations of the the commands, so I don't want redundant code everywhere in my implementations. Is it possible to put these two things in the abstract class, if yes please tell me how.
If not please explain it to me why it isnt possbile. Or if I need to change something to do it, anyhow.
regards
YES WE CAN!
I have a class called Singleton that is abstract... and many classes that extends that Singleton class... this is the code:
abstract class Singleton {
private static $instances = array();
final private function __construct($_params) {
$class = get_called_class();
if (array_key_exists($class, self::$instances))
throw new Exception('An instance of '. $class .' already exists !');
//static::initialize(); //In PHP 5.3
$this->initialize($_params);
}
final private function __clone() { }
abstract protected function initialize();
public static function getInstance($_params=array()) {
$class = get_called_class();
if (array_key_exists($class, self::$instances) === false){
self::$instances[$class] = new $class($_params);
}
return self::$instances[$class];
}
}
and (for example) the class DBConnection that extends from Singleton
class DBConnection extends Singleton{
private $connexion_pdo=null;
protected function initialize(){
//connect to the DB
$this->connexion_pdo = blablalba;
}
}
although there are some problems in php 5.2.. specially with the function get_called_class() and the static::initialize()
You could also check the php site for patterns... there are lots of contributions for the singleton
Good Luck

Categories