How to encapsulate a file include? - php

If I have a class that includes a file with a constant like so:
define("FOO", "bar");
Is there a way to make the class include the file with encapsulation so if I use the class somewhere that already has a FOO constant defined it won't break?

Create a static class and use constants would be the best way to encapsulate specific constants:
static class Constants
{
const Name = 'foo';
const Path = 'Bar';
}
And then use like so:
echo Constants::Name; //foo
echo Constants::Path; //bar
in regards to the precheck you can do
function _defined($key,$check_classes = false)
{
if($check_classes)
{
foreach(get_declared_classes() as $class)
{
if(constant($class . '::' . $key) !== null)
{
return true;
}
}
}
if(!defined($key)) //global Scope
{
return true;
}
}
Usage:
class a
{
const bar = 'foo';
}
if(_defined('bar',true)) //This would be true because its within a
{
//Blah
}
If your thinking of a situation like so
class a
{
const b = '?';
}
class b
{
const b = '?';
}
the constants are within the class scope so they would have no affect on one another !

You can check if constant already defined using defined:
<?php
define("FOO", "1");
if (!defined("FOO")) { ## check if constant is not defined yet
define("FOO", "2");
}
echo FOO;
?>

You can use a class contant
class Foo
{
constant FOO = 'bar'
}
However, you will have to include the class before you can use the constant with Foo::FOO. An alternative with regular constants is to use to prefix them with a vendor prefix to make clashes less likely, e.g.
define('JOHN_FOO', 'bar')
or use the newly introduced namespaces (PHP 5.3)
define('JohnIsaacks\FOO', 'bar');
But in all cases, I wonder why you would need that. If you want to load classes, simply add in an autoloader.

Related

Use unknown class in the another class

I want to use an unknown class with a variable in another class:
Example
$classandmethod = "index#show";
namespace Lib\abc;
use Lib\xyz;
class abc{
function controller($classandmethod)
{
$a = explode("#", $classandmethod);
use Lib\Controller\.$a[0];
}
}
But maybe it's not true, please help everyone!
From the manual:
The use keyword must be declared in the outermost scope of a file (the global scope) or inside namespace declarations
So you can't use a class where you're trying to do it. Then, to instantiate a class from a different namespace from a variable, rather than useing it, supply the whole namespaced class:
<?php
namespace G4\Lib
{
class A
{
public $a = "test";
}
}
namespace G4
{
class B
{
public $a;
public function __construct($class)
{
$class = "\\G4\\Lib\\".$class;
$this->a = new $class; // here's the magic
}
}
$b = new B("A");
var_dump($b->a); // test
}
Demo
The main problem is that use cannot have a variable as part of it as it's used when parsing the file and the variable is only available at runtime.
This is an example of how you can do what you seem to be after...
<?php
namespace Controller;
ini_set('display_errors', 'On');
error_reporting(E_ALL);
class Index {
public function show() {
echo "Showing...";
}
}
$classandmethod = "Controller\Index#show";
list($className,$method) = explode("#", $classandmethod);
$a= new $className();
$a->$method();
This displays...
Showing...
You could of course say that all of these classes must be in the Controller namespace and so the code will change to
$classandmethod = "Index#show";
list($className,$method) = explode("#", $classandmethod);
$className = "Controller\\".$className;
$a= new $className();
$a->$method();

Access constant without self::?

I'd like to use some constants with a function, but it is laborious and ugly to refer to them with self:: every time. Is there a way to just access them by name without specifying scope?
class My_Class {
const CLASS_CONSTANT = 'test value';
private function my_function(){
// Is there a way to access this without self::
$a = self::CLASS_CONSTANT;
}
}
One possible (but clunky) way to achieve this, is using the define() function. The only problem with this approach is that it defines the variable in a global scope.
Here is how to use it:
define ('text', 'Foo Bar?!');
echo text;
Will return: Foo Bar?!
So to integrate this into a class you can do the following:
class My_Class{
function __construct(){
define ('CLASS_CONSTANT', 'test value');
}
private function display(){
echo CLASS_CONSTANT;
}
}
$example = new My_Class();
$example->display();
This outputs: test value
Do note that define() is a function, and as such requires to be executed inside of a function block, or outside of the class. It can not be easily declared at the top of a class like normal class constants.
You can use ReflectionClass to get all the constants of a class
$oClass = new \ReflectionClass(My_Class::class);
$constants = $oClass->getConstants();
foreach ($constants as $name => $value) {
//to work
}
For more visit: http://php.net/manual/en/reflectionclass.getconstants.php
Hope it helps!

PHP 5.4: Getting Fully-qualified class name of an instance variable

I know there is a static class field on PHP 5.5, but I have to stick to PHP 5.4. Is it possible to get the fully qualified class name from a variable?
Example:
namespace My\Awesome\Namespace
class Foo {
}
And somewhere else in the code:
public function bar() {
$var = new \My\Awesome\Namespace\Foo();
// maybe there's something like this??
$fullClassName = get_qualified_classname($var);
// outputs 'My\Awesome\Namespace\Foo'
echo $fullClassName
}
You should be using get_class
If you are using namespaces this function will return the name of the class including the namespace, so watch out if your code does any checks for this.
namespace Shop;
<?php
class Foo
{
public function __construct()
{
echo "Foo";
}
}
//Different file
include('inc/Shop.class.php');
$test = new Shop\Foo();
echo get_class($test);//returns Shop\Foo
This is a direct copy paste example from here
I know this is an old question, but for people still finding this, I would suggest this approach:
namespace Foo;
class Bar
{
public static function fqcn()
{
return __CLASS__;
}
}
// Usage:
use Foo\Bar;
// ...
Bar::fqcn(); // Return a string of Foo\Bar
If using PHP 5.5, you can simply do this:
namespace Foo;
class Bar
{}
// Usage:
use Foo\Bar;
// ...
Bar::class; // Return a string of Foo\Bar
Hope this helps...
More info on ::class here.
For developers using PHP 8.0 and above, you can now easily do this without get_class.
PHP8 introduced the support for ::class on objects. Example:
public function bar() {
$var = new \My\Awesome\Namespace\Foo();
echo $var::class;
}
Here's the RFC for more info.

Cannot access class constant from an instance using the :: scope operator

I hit a strange problem today and even as a PHP engineer i'm stumped at this:
It seems you can access a class constant from an object instance such as:
class a {
const abc = 1;
}
$a = new a();
var_dump($a->abc);
This will output null instead of the expected 1. I was able to do the following:
class a {
const abc = 1;
}
$a = new a();
var_dump(a::abc);
But in the context of a sub object that doesn't really know who the parent is exactly, i find it extremely annoying to do:
class a {
const abc = 1;
}
$a = new a();
$c = get_class($a);
var_dump($c::abc);
Is it me or this is completly stupid, if not, please enlighten me why its working that way.
EDIT
Another way of doing it but it's not really better:
class a {
const abc = 1;
}
class b {
public function getA(){
return new a();
}
}
$b = new b();
$c = $b->getA();
var_dump($c::abc);
This last example works more like what i am doing and experiencing...
Just use the instance variable with the scope resolution operator:
$a = new a();
var_dump($a::abc);
This prints 1.
I found a relatively nice and clean way to make my problem easier to live with. Here is the solution i've applied. It is not necessarely the best but for my uses it does exactly what i need.
By creating a magic __get method, i intercept the request for the constant name from and instance point of view and i use a quick reflection to see if that constant exists and return it's value.
This allows me to actually use all in one line a pattern that looks like this:
class a {
const abc = 1;
public function __get($key){
$r = new ReflectionObject($this);
if($r->hasConstant($key)){ return $r->getConstant($key); }
}
}
class b {
public function getA(){
return new a();
}
}
$b = new b();
var_dump($b->getA()->abc);
var_dump($b->getA()->def);
Althought i'd have liked to do:
var_dump($b->getA()::abc);
var_dump($b->getA()::def);
I guess this could be possible later in 5.4+ considering we finaly have array dereferencing, we could probably ask them to add static dereferencing soon.
The PHP documentation indicates that class constants are accessed via SRO (::) rather than ->.
<?php
class MyClass
{
const constant = 'constant value';
function showConstant() {
echo self::constant . "\n";
}
}
echo MyClass::constant . "\n";
ike I mentioned, in php constants are tied to the class definition, they are static by definition and cannot be accessed using the -> operator.
If you really want to use it with your coding paradigm, you can try the reflection class in php5.
class MyClass
{
const A = "I am A";
}
$o = new ReflectionClass( "MyClass" );
echo $o->getconstant("A"); //will print "I am A"
Also, I think the example in your EDIT might not work..I did not run it, but I am not sure if the SRO(::) can be invoked on anything that is not a class reference..
I know this is an old thread, but for people who want to know the best way to do this have a look at the PHP function constant().
With constant() you can simply do this:
$a = new a();
$value = constant(get_class($a)."::abc");
// $value === 1
this has been available since PHP 4, and still works perfectly in PHP 5.5
When trying to use const defined in a class inside a different namespace, the Scope Resolution Operator (::) can be used without problems as stated by the docs prefixing the namespace before the class in which the const was declared with this format:
(<namespace>"\")*<className>::<const>
With the next namespace, class and const definitions:
models/OperationModel.php
<?php
namespace models;
class OperationModel {
const OPERATION_INITIALIZING = 1;
}
You can use the const from another namespace\class like this:
controllers/MobileController.php
<?php
namespace controllers;
use models\OpertionModel;
class MobileController {
private function thingy() {
$operation_status = models\OperationModel::OPERATION_INITIALIZING;
}
}

PHP encapsulation without class?

Is it possible to encapsulate, a variable or function let say, in PHP without wrapping them in a class? What I was doing is:
//Include the file containing the class which contains the variable or function
include('SomePage.php');
//Instantiate the class from "SomePage.php"
$NewObject = new SomeClassFromSomePage();
//Use the function or variable
echo $NewObject->SomeFuncFromSomeClass();
echo $NewObject->SomeVarFromSomeClass;
My intention is to avoid naming conflict. This routine, although it works, makes me tired. If I cannot do it without class, it is possible not to instantiate a class? and just use the variable or function instantly?
To use class methods and variables without instantiating, they must be declared static:
class My_Class
{
public static $var = 123;
public static function getVar() {
return self::var;
}
}
// Call as:
My_Class::getVar();
// or access the variable directly:
My_Class::$var;
With PHP 5.3, you can also use namespaces
namespace YourNamespace;
function yourFunction() {
// do something...
}
// While in the same namespace, call as
yourFunction();
// From a different namespace, call as
YourNamespace\yourFunction();
PHP Namespaces were made to archive the exact same goal:
<?php // foo.php
namespace Foo;
function bar() {}
class baz {
static $qux;
}
?>
When using call namespaced functions like this:
<?php //bar.php
include 'foo.php';
Foo\bar();
Foo\baz::$qux = 1;
?>
This is a way to encapsulate without Class
<?php
(function (){
$xyz = 'XYZ';
})();
echo $xyz; // warning: undefined
Encapsulation Alternative
With this method you can minimize unintentional using array key(uses it instead of variables). Can also use value stored in array anywhere after assigning. Shorter array key area length with variable in keys, inside encapsulation function; outside encapsulation function, variables can be used in keys but otherwise long discriptive keys. Nested encapsulation can also be used.
Example
<?php
define('APP', 'woi49f25gtx');
(function () {
$pre = 'functions__math__'; // "functions" is main category, "math" is sub.
$GLOBALS[APP][$pre . 'allowedNumbers'] = [3,5,6];
$GLOBALS[APP][$pre . 'square'] = function ($num) {
return $num * $num;
};
$GLOBALS[APP][$pre . 'myMathFunction'] = function ($num) use ($pre) {
if(in_array($num,$GLOBALS[APP][$pre . 'allowedNumbers'])) return 'not allowed';
return $GLOBALS[APP][$pre . 'square']($num);
};
})();
echo $GLOBALS[APP]['functions__math__myMathFunction'](4);

Categories