Reputation: 1
I want function explicitSetX( $value){} to be public in a specific task otherwise it should be private. (functionality of private)
(Im not interested in how to write generic setters, this question is about Visibility / Accesibility)
class My_Object{
public function genericArrSetter ( $property, $value ){
$this->$property = $value;
}
}
class Obj extends My_Object{
private $x;
private $x1;
private $x2;
private $x3;
private $x4;
private $x5;
private $x6;
private $x7;
private $x8;
public function explicitSetX( $value){
$this->XX = $value;
}
}
/*
* Below functions run from outside
* I would like to force this behaviour since now
* its possible for others to use myStart. (way of setting)
*/
function myStart (){
// set all data in Obj via generic setter
$obj = new Obj();
$obj-> genericArrSetter("x","value for x");
}
function OtherStart (){
// set all data in Obj via explicit setter
$obj = new Obj();
$obj-> explicitSetX ("value for x");
}
Upvotes: 0
Views: 112
Reputation: 17361
The only feasible way of doing that is by using interfaces and type hinting.
Declare two interfaces:
interface ExplicitSetter {
public function setExplicitX($value);
}
interface GenericSetter {
public function setGeneric($x, $value);
}
Your class implements both.
class MyObject implements ExplicitSetter, GenericSetter {
private $x;
public function setExplicitX($value) {
$this->x = $value;
}
public function setGeneric($x, $value) {
$this->x = $value;
}
public function __toString() {
return $this->x;
}
}
Now you can use type hinting to only expose the interface you are interested in. Trying to use methods not declared by the interface will result in a error.
function useExplicitSetter(ExplicitSetter $setter) {
$setter->setExplicitX('Hello explicit');
}
function useGenericSetter(GenericSetter $setter) {
$setter->setGeneric('x', 'Hello generic');
}
Usage:
$obj = new MyObject();
useExplicitSetter($obj);
echo $obj; // Hello explicit
useGenericSetter($obj);
echo $obj; // Hello generic
http://sandbox.onlinephpfunctions.com/code/a7a7a4c4566b529762d4eea755c11a8a9a8734d4
Upvotes: 0
Reputation:
This is hakish and not recommended but you could do something like that:
class My_Object{
// Final will disallow ovverriding
public final function genericArrSetter ( $property, $value ){
// Get caller function name
$callers = debug_backtrace();
// If it's not myStart do something more or less nasty
if($callers[1]['function'] !== 'myStart')
{
throw new Exception('This is not allowed');
}
$this->$property = $value;
}
}
Example:
function myStart (){
// set all data in Obj via generic setter
$obj = new Obj();
$obj-> genericArrSetter("x","value for x");
}
function OtherStart (){
// set all data in Obj via explicit setter
$obj = new Obj();
$obj-> explicitSetX ("value for x");
// Below will throw exception
$obj-> genericArrSetter("x","value for x");
}
For more robust solutions for caller name see this: How to get name of calling function/method in PHP?
DISCLAIMER: Not tested not recommended
Upvotes: 0
Reputation: 519
Why declare your attributes private if you want to access them publicly? In any case, you can use the magic method __set() to write data to private/protected variables
public function __set($name, $value){
$this->$name = $value;
}
Alternatively you could pass the values into the constructor function:
public function __construct($A, $B, $C){
$this->A = $A;
$this->B = $B;
$this->C = $C;
}
You could use an associative array as the argument instead with a foreach loop:
public function __construct(array $args){
foreach ($args as $key=>$value){
$this->$key = $value;
}
}
The constructor's signature should probably be __construct(array $args=null) so you can use new Obj($args) and new Obj() but you will have to check in the body if $args is not empty.
Upvotes: 1