PHP Class Constants - Public, Private or Protected? - php

Am I correct in assuming that const properties are automatically public? Is there a way to make them private or protected?
Thanks in advance.

Historically, class constants were always publicly accessible as long as the class was loaded and there was no way to change this.
As of PHP 7.1, they remain public by default but access modifiers may now be applied. Here's the example from the release notes:
<?php
class ConstDemo
{
const PUBLIC_CONST_A = 1;
public const PUBLIC_CONST_B = 2;
protected const PROTECTED_CONST = 3;
private const PRIVATE_CONST = 4;
}

Class constants should have the option of being private/protected because being public exposes internal details of the class that other classes/code can mistakingly use thinking they are ok to use because they are public.
It would be nice to know that changing a private constant would ONLY affect the class it's defined in. Unfortunately we don't have that option.
Remember back to when you were learning Object Design & Analysis... you give class methods and attributes the most RESTRICTIVE access possible, and later relax them as needed (much harder to go back the other way because other classes/code start using them which would then break other code).
WORKAROUND
Best bet is to just create a private or protected variable and upper-case it to show it's a constant. You could always create a class called constant($value_to_be_constant) that implements the correct magic methods / spl interfaces to prevent it from being changed.

I am aware this question is 6 years old
Php 7.1 (currently RC1) allows to specify visibility on class constants.
class Token {
// Constants default to public
const PUBLIC_CONST = 0;
// Constants then also can have a defined visibility
private const PRIVATE_CONST = 0;
protected const PROTECTED_CONST = 0;
public const PUBLIC_CONST_TWO = 0;
//Constants can only have one visibility declaration list
private const FOO = 1, BAR = 2;
}
Additional info
RFC on class const visibility
Blog post on Class Constant Visibility

As of php7.1, you can define your class constants with access modifiers (public, private or protected). Have a look at the following example:
<?php
class superheroes{
public const kal_el = 'Superman';
protected const bruce_wayne = 'Batman'; # works php7.1 onwards
private const anthony_stark = 'Iron Man'; # works php7.1 onwards
public static function show_remaining(){
echo self::bruce_wayne, '<br />';
echo self::anthony_stark, '<br />';
}
}
echo superheroes::kal_el, '<br />';
superheroes::show_remaining();
Credits: http://dwellupper.io/post/48/defining-class-constants-in-php

Related

How to use a prefix in derived class constants in PHP?

I would like to create a helper class for icon constants, but there is two types for every icon. I try to avoid duplication, so I make some inheritance.
As I understand the concept of constanst, this will never work, but I do not know what would be a better solution. Could you suggest a clean solution for this problem? The aim would be to avoid the need for remembering every constant. Thanks!
abstract class Heroicon
{
protected const PREFIX = "";
public const ACADEMIC_CAP = self::PREFIX . "academic-cap";
public const ADJUSTMENTS = self::PREFIX . "adjustments";
// ... +200 rows
}
class HeroiconSolid extends Heroicon
{
protected const PREFIX = "heroicon-s-";
}
class HeroiconOutline extends Heroicon
{
protected const PREFIX = "heroicon-o-";
}
echo HeroiconSolid::ACADEMIC_CAP; // "academic-cap" instead of "heroicon-s-academic-cap"

Why declare class' properties when constructor initialize this properties

Write what is best and why?
class Chat
{
private $_couleur;
private $_race;
function __construct($couleur, $race)
{
$this->_couleur = $couleur;
$this->_race = "$race";
}
public function getCouleur() {
return $this->_couleur;
}
}
Or
class Chat
{
function __construct($couleur, $race)
{
$this->_couleur = $couleur;
$this->_race = "$race";
}
public function getCouleur() {
return $this->_couleur;
}
}
Because $this->_couleur is initialized when the class is instancied, so declare the property directly in the class is useless, isn't ?
Declaring the variables at the top of your class is a very good practice, because it makes it clear to anyone that reads your code which properties the class has private and which properties the class has public.
In the second example your variables will be public because they're dynamically generated.
When your constructor would be much bigger it is a pain in the ass as developer to find out where your variables are introduced.
It is also good to set default values (if they are always the same) to the variables in the class as opposed to the constructor. It makes your code more readable and understandable.
First block of code is better from the second, But one thing in first block.
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.
This code collected from php.net
<?php
class Test
{
private $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
private function bar()
{
echo 'Accessed the private method.';
}
public function baz(Test $other)
{
// We can change the private property:
$other->foo = 'hello';
var_dump($other->foo);
// We can also call the private method:
$other->bar();
}
}
$test = new Test('test');
$test->baz(new Test('other'));
?>
Output:
string(5) "hello"
Accessed the private method.
The first one is better. You are actually declaring your variables as private, giving them a meaningful scope. The second version is more error-prone.
Just wanted to add one simple benefit of declaring class properties: Any good IDE will parse and build a symbol table out of your declared class properties. So if you are writing a class and start typing $this->, a list of your declared properties will show up so you can easily select the one you want to use. If you create variables in your constructor without declaring them, your IDE won't be able to see them.

$new = new self($data); with private functions and even variables oO?

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...

PHP5 member visibility

Could someone explain me, why is it possible to do the following in PHP, but, for example, not in C# or Java:
Class A {
protected $a = 'Howdy!';
}
Class B extends A {
public function howdy() {
$created = new A();
echo $created->a; <----- This is legal due to per-class visibility
}
}
$b = new B();
echo $b->howdy(); <----- Hence, no fatal error here
This behavior seems to be specified here, but I can't understand the fundamental reason behind this (to my mind, one can't simply implement the per-class visibility instead of the per-instance one without having a strong reason for that).
The reason it doesn't work is, as you specified, PHP implements access control on a class level, where other languages use an instance level approach.
Why is it useful? It allows your classes to operate on other instances of itself without exposing its private data. Let's take a simple value-object example:
class Int {
protected $value = 0;
public function __construct($value) {
$this->value = (int) $value;
}
public function add(Int $new) {
return new Int($new->value + $this->value);
}
}
$a = new Int(1);
$b = new Int(2);
$c = $a->add($b);
This lets you keep protected info encapsulated, yet still work with it across instances...
There are pros and cons to both approaches...
That is also possible in C# (and Java for that matter).
class A // declare new class type B
{
protected string a = "Howdy!"; // that has a protected member called `a`
}
class B : A // declare new type B which extends type A
{
public void howdy()
{
A created = new A();
Console.WriteLine(created.a); // no problem accessing a b/c B extends A
}
}
B bInst = new B(); // create a new instance of type B
bInst.howdy(); // invoke it's public method howdy()
Basically what is going on is this:
class A contains a protected member called a which means it is visible in the scope of classes which extend A (in our case class B)
class B extend a so it has access to it's protected members (in our case to a)
It is possible to do in both C# and Java as well. protected means the variable is accessible from any subclass of A. B is a subclass of A, hence it can access the variable. There's no magic here.
The page you linked to has a section titled "Visibility from other objects" which states that:
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.
It wouldn't work if you'd done this:
$b = new B();
echo $b->a;
In your example, you're not accessing the $a member direct from B(). You're accessing it from an A() object that happens to have been instantiated from inside B().

Php abstract class site configuration

i have a config class which is an abstract class. I would like to set it up so it automatically detects which server the site is on and then assigns appropriate constants. I get an error on line ten $this->hostName = $_SERVER['SERVER_NAME']; expecting `T_FUNCTION.
What is the correct way to do this and is there a better way to do this? Here is the first part of my class
abstract class config{
public $hostName;
public $hostSlices;
public $domain;
echo $_SERVER['SERVER_NAME'];
//strips out the "www" from the server name but only if it has the name on it .
$this->hostName = $_SERVER['SERVER_NAME'];
$this->hostSlices = explode(".",$this->hostName);
if($this->hostSlices[0]=="www"){array_shift($this->hostSlices);}
$this->domain = join(".",$this->hostSlices);
//depending on which domain is used, different config setup is used.
switch ($this->domain){
case "localhost":*/
const HOST = "localhost";//would http://localhost/ work as well. In that case, then this and the SITE_ROOT could be the same variable and i would preferentially set them depending on the host that the site is on.
const USER = "root";
const PWD = "xxxxxxx";
const NAME = "hurunuitconz";//database name
//public $name = "hello from the config class";//you cannot access variables from an abstract class you should define constants and then the can be used anywhere
###########Location of file groups########
const SITE_ROOT = "http://localhost";
const ADMIN_IMAGES = 'http://localhost/images/user_images/admin_images';
break;
case "charles.hughs.natcoll.net.nz":
const HOST = "charles.hughs.natcoll.net.nz";//would http://localhost/ work as well. In that case, then this and the SITE_ROOT could be the same variable and i would preferentially set them depending on the host that the site is on.
const USER = "charles_andrew";
const PWD = "xxxxxxx";
const NAME = "charles_hurunuitconz";//database name
###########Location of file groups########
const SITE_ROOT = "http://charles.hughs.natcoll.net.nz/_Assignments/Industry/www";//this is just confusing the way natcoll makes us do this.
const ADMIN_IMAGES = 'http://charles.hughs.natcoll.net.nz/_Assignments/Industry/www/images/user_images/admin_images';
break;
}
An abstract class shouldn't allow you to set private data (only an inherited concrete class).
Also, take a look at this link in stackoverflow for an interesting discussion on SERVER_NAME vs. HTTP_HOST
You have to wrap all that code in a constructor or better yet a function called init() or somthing. Then when you override init in the child classes you would call parent::init(). Did you mean to make this class static, not abstract?
The way you're structuring your code is just not right. PHP does allow for many crazy things, but defining constants and outputting code as a part of an abstract class makes no sense whatsoever in terms of OOP.
What you probably mean to do is to have a helper class that defines configuration settings based upon the local server name. To do so, you have a couple options:
Option 1) Create a regular class with a constructor.
class Config {
public $x;
public $y;
public function __construct() {
switch (...) {
$this->x = 2;
$this->y = 3;
}
}
}
And use it like this:
$config = new Config();
echo "Variable y: " . $config->y;
Option 2) Static method in an abstract class.
abstract class Config {
public $boolInitialized = false;
public static function init() {
if (self::$boolInitialized) {
return;
}
self::$boolInitialized = true;
switch (...) {
self::$x = 1;
self::$y = 2;
}
}
public static function getX() {
self::init();
return self::$x;
}
}
And use it like this:
echo Config::getX();
You cant output something in a class without declaring first a method
this will fail
abstract class fo
{
public $fo;
echo $fo;
}
**but this will work**
abstract class fo
{
public $fo;
public function __construct()
{
$this->fo = $_SERVER['SERVER_NAME'];
}
public function sayFo()
{
echo $this->fo;
}
}

Categories