This is probably a basic question but im following this tutorial and at one point the code looks something like this.
<?php
class person
{
public $name;
public $height;
protected $social_security_no;
private $pin_number = 3242;
public function __construct($person_name)
{
$this->name = $person_name;
}
public function set_name($new_name)
{
$this->name = $new_name;
}
protected function get_name()
{
return $this->name;
}
public function get_pin_number_public()
{
$this->pub_pin = $this->get_pin_number();
return $this->pub_pin;
}
private function get_pin_number()
{
return $this->pin_number;
}
}
class employee extends person
{
public function __construct($person_name)
{
$this->name = $person_name;
}
protected function get_name()
{
return $this->name;
}
}
However when i use this
<?php include "class_lib.php";?>
</head>
<body id="theBody">
<div>
<?php
$maria = new person("Default");
$dave = new employee("David Knowler");
echo $dave->get_name();
?>
i get this error
Fatal error: Call to protected method employee::get_name() from
context '' in C:\Users\danny\Documents\Workspace\test\index.php on
line 13
The problem seems to be when i add protected to the get_name() function in the employee class but it seems to me that this is the preferred way to override in the tutorial. Any ideas?
The problem isn't that you cannot override the protected method, it's that you are calling a protected method from outside of the class.
After the class is instantiated, you can call a public method which in turn could call get_name() and you will see that the code will work as expected.
For example:
class employee extends person {
function __construct($person_name){
$this->name = $person_name;
}
protected function get_name() {
return $this->name;
}
public function name()
{
return $this->get_name();
}
}
$dave = new employee("David Knowler");
echo $dave->name();
In your example, you would probably be best making get_name() public.
"The problem seems to be when i add protected to the get_name() function in the employee class" -- this is your answer. A protected method can only be called from the very same class or subclasses, not "from the outside". Your method has to be public if you want to use it this way.
You can access get_name() within person class or employee class not outside of these two classes.
check protected visibility
http://php.net/manual/en/language.oop5.visibility.php
Related
i want to show a name.name may be in uppercase or in lowercase this will be depend on which class i will pass.i have to approach one is using class and second is interface which one is better and why ?
Solution using Class
class User{
}
class Iuser extends User{
private $name;
function __construct($name){
$this->name = $name;
}
function getName(){
return strtoupper($this->name);
}
}
class Wuser extends User{
private $name;
function __construct($name){
$this->name = $name;
}
function getName(){
return strtolower($this->name);
}
}
class Name{
public $u;
function __construct(User $u){
$this->u = $u;
}
function getName(){
$name = $this->u->getName();
return "Hi My Name is ".$name;
}
}
$name = "Deval Patel";
$iu = new Iuser($name);
$wu = new Wuser($name);
$user = new Name($wu);
echo $user->getName();
Solution Using Interface
interface User{
public function getName();
}
class Iuser implements User{
private $name;
function __construct($name){
$this->name = $name;
}
function getName(){
return strtoupper($this->name);
}
}
class Wuser implements User{
private $name;
function __construct($name){
$this->name = $name;
}
function getName(){
return strtolower($this->name);
}
}
class Name{
public $u;
function __construct(User $u){
$this->u = $u;
}
function getName(){
$name = $this->u->getName();
return "Hi My Name is ".$name;
}
}
$name = "Deval Patel";
$iu = new Iuser($name);
$wu = new Wuser($name);
$user = new Name($iu);
echo $user->getName();
Using the interface solution the getName() method is defined but not implemented in User interface (not shown in your code), so each class implementing it has to define the behaviour to get the name, whilst using abstract classes you may define the standard way to get the name, and override or overload the method in child classes when necessary.
So for your code, I think the best solution is the abstraction.
Remember to use interfaces when you want to force the developer to code the getName() method, and for abstract classes just to allow the developer to use the parent method getName(), or override/overload if necessary. Interfaces gives you more control and code reutilization.
Review the PHP object interfaces doc and PHP class abstraction doc, it may shed some light on your doubt.
I would use classes because you can reuse some code.
abstract class User
{
protected
$name;
public function __construct($name)
{
$this->name = $name;
}
abstract function getName();
}
class Iuser extends User
{
public function getName()
{
return strtoupper($this->name);
}
}
class Wuser extends User
{
function getName(){
return strtolower($this->name);
}
}
This way you can still use polymorphism and reuse some common code.
It's better then interface because the code reuse. You can still use an interface for the abstract class User but I think it would be an overkill.
i'm having a trouble at the moment that i'm trying to access from a method of Wolf class to other method of Dog class. That's the code:
index.php
require_once 'Wolf.php';
require_once 'Dog.php';
class StackOverflowExample{
public static function run(){
$dog = new Dog("Cokey");
$wolf = new Wolf("Wolfenstein");
$wolf->hunt();
}
}
StackOverflowExample::run();
Wolf.php
class Wolf {
private $_name;
public function __construct($name){
$this->_name = $name;
}
public function hunt(){
return $dog->setLife(0);
}
}
Dog.php
class Dog {
private $_name;
private $_life= 100;
public function __construct($name){
$this->_name = $name;
}
public function setLife($life){
$this->_life = $life;
}
public function getLife(){
return $this->_life;
}
}
It gives me the next errors:
· Undefined variable: dog
· Call to a member function setLife() on a non-object
I have spent two days searching and I still having no way to fix.
Thanks you and sorry for my bad english.
What you should do is to pass $dog around, in the hunt method, like this:
public function hunt(Dog $dog){
return $dog->setLife(0);
}
You get the ability to validate that the dog variable is an instance of the expected class.
This method of passing objects around is called dependency injection.
If you want to pass around all sorts of animals you need to use another concept called inheritance:
abstract class Animal
{
public $_life;
public function setLife($life){
$this->_life = $life;
}
public function getLife(){
return $this->_life;
}
}
class Dog extends Animal
{
private $_name;
public function __construct($name){
$this->_name = $name;
}
}
class Wolf {
private $_name;
public function __construct($name){
$this->_name = $name;
}
public function hunt(Animal $animal){
return $animal->setLife(0);
}
}
Notice that the common methods and variables live in the parent class, and that you can create as many types as animals as you want.
If you follow this example you should find a way to declare the animal's name variable in the Animal class so you don't have to redefine it in all subclasses ;)
Replace
$dog->setLife(0);
by
Dog::setLife(0);
I've been programming mainly with JAVA and have written procedural programs in PHP, but now I'm try to write some OOP bases programs in PHP and I'm facing a problem.
I've got two files , Zoo.php and Dog.php , each contains a class.
Dog.php:
<?php
class Dog {
private $name;
private $color;
public function __construct($name,$color) {
$this->name = $name;
$this->color = $color;
}
public function getName(){
return $this->name;
}
public function getColor(){
return $this->color;
}
}
And Zoo.php:
<?php
class Zoo {
private $name;
private $dogs;
public function __construct($name) {
$this->name = $name;
$dogs = array();
}
public function addDog($dogName,$dogColor){
$dog = new Dog($dogName,$dogColor);
array_push($this->dogs,$dog);
}
public function getAllDogs(){
var_dump($dogs);
}
}
echo "start";
$z = new Zoo("test_zoo");
$z->addDog("blackie","black");
$z->getAllDogs();
The code above outputs :
Fatal error: Class 'Dog' not found in C:\wamp\www\Zoo.php on line 13
I'd like to know what's wrong with the code above and how creating an object instance within another object should be done in PHP. Thanks in advance.
I gues you are not including Dog class.
<?php
include "Dog.php";
class Zoo {
/* ... */
}
Or you can use autoloading to auto include any class by default.
It's not about OOP. Just you forgot to include Dog file to use it you Zoo class :
<?php
include 'Dog.php'; // or whatever path
class Zoo { ...
Everything else should be ok and seems to be a good use of PHP OOP btw. :)
You haven't included your Dog.php in your Zoo.php. Therefore you can't create an new instance.
Just above class Zoo add this:
include("Dog.php");
class Zoo {
All you need to return function .
Three mistakes here, u'll see all of them in my code . Constructer nothing return , behave like void , so we need a method that returns dog specification.If you wanna use the classes in separate file, so u've to use php method that "include" or "require" or "require_once" etc ( see the difference of this method)
<?php
class Dog {
private $name;
private $color;
public function __construct($name,$color) {
$this->name = $name;
$this->color = $color;
}
public function getName(){
return $this->name;
}
public function getColor(){
return $this->color;
}
public function getDogs(){
return array("name"=>$this->name,"color"=>$this->color);
}
}
class Zoo extends Dog{
private $name;
private $dogs=array();
public function __construct($name) {
$this->name = $name;
$dogs = array();
}
public function addDog($dogName,$dogColor){
$dog = new Dog($dogName,$dogColor);
array_push($this->dogs,$dog->getDogs());
}
public function getAllDogs(){
var_dump($this->dogs);
}
}
echo "start";
$z = new Zoo("test_zoo");
$z->addDog("blackie","black");
$z->getAllDogs();
?>
I have two classes involving composition not inheritance., class A and class B. One of class A's properties is an array of class B objects. Class A has a public method A::getName(). Class B also has a public method with the same name. The method for class A is as follows:
public function getName()
{
return $this->_name;
}
My problem is when I'm in Class B and I try to access this public method for class A, I get the "cannot access protected property" error. $_name is a private property in each class. Class A's would be the name, for example, of a form, and for B, the name of the field.
This is the code that generates the error (constructor for class B):
public function __construct($name)
{
$this->foo = A::getName() .'-'. $name;
}
Why is it not allowing me to access class A's public method getName()? Any way to fix or get around this?
FIX:
I realized I was invoking class A's method statically, though I need to deal with each object individually, as each object has a unique name. To solve my issue I gave a public set function for class B for the unique name, and called that in class A:
class A
{
...
$this->list[$B_name] = new B($B_name);
$this->list[$B_name]->setID($this->_name, $B_name);
}
class B
{
...
public function setID($name, $subName)
{
$this->foo = $name .'-'. $subName;
}
This is because of you are trying to call it statically and in that method you are accessing instance variable.
it could work like this:
class A {
private static $_name = "A";
public static function getName() {
return self::$_name;
}
}
class B {
public function __construct($name) {
$this->foo = A::getName() .'-'. $name;
}
}
or this way (this is imho your situation)
class A {
private $_name;
public function __construct($name) {
$this->_name = $name;
}
public function getName() {
return $this->_name;
}
}
class B {
public function __construct($name, A $parent) {
$this->foo = $parent->getName() .'-'. $name;
}
}
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.