2

Is there any professional way to set the visibility of a method to internal/package inside my namespace?

Example:

namespace ExampleFramework;

class Request {
   ...

   public function getResponse() {
       return new Response(...); // Should work
   }
}

class Response {
   internal function __construct(...) {
      ...
   }
}

namespace AnotherFramework;

$request = new Request();
$response = $request->getResponse(); // Should work
$wrongResponse = new Response(...); // Should NOT work
Luca Nate Mahler
  • 1,292
  • 2
  • 13
  • 28
  • 2
    No, PHP doesn't have that. – deceze Mar 13 '14 at 11:17
  • "professional" just means you get paid to do it nothing more. – PeeHaa Mar 13 '14 at 11:27
  • Also to me it looks like you are something very not OOP. So soncidering you tagged it OOP: *why* on earth are you trying to do this? – PeeHaa Mar 13 '14 at 11:27
  • I can tell you why: it's normal in frameworks that there are classes which only can be created (the objects) by framework-intern classes, for example an XMLReader which gives you the XML-structure as an object of the class XMLElement. The framwork calls methods like addAttribute(...) or addChild(...), but the user of the framwork should only be able to "read" like getAttributes() and so on, but NOT manipulate it. So the "write"-methods are not public nor private, they must be internal/package. – Luca Nate Mahler Mar 13 '14 at 11:34
  • Are you sure you aren't simply talking about private / protected setters and public getters?? – PeeHaa Mar 13 '14 at 11:43
  • And how can the XMLReader-class set (add) a XML-attribute of the XMLElemet-object if its setter's is private or protected? – Luca Nate Mahler Mar 13 '14 at 13:33
  • possible duplicate of [PHP friend/package visibility](http://stackoverflow.com/questions/7292433/php-friend-package-visibility) – Markus Malkusch Apr 01 '14 at 01:33

3 Answers3

2

PHP doesn't have a language construct to enforce that visibility. IMO the best you can do is use phpDocumentor's @internal and hope that the API user follow's the contract:

The @internal tag can be used as counterpart of the @api tag, indicating that the associated Structural Elements are used purely for the internal workings of this piece of software.

Markus Malkusch
  • 7,738
  • 2
  • 38
  • 67
0

You can use private constructor in Response class:

class Request {
   ...

   public function getResponse() {
       return Response::getInstance(...);
   }
}

class Response {

  private function __construct(...) {
  }

  public static getInstance(...) {
    return new Response(...);
  }

}
hsz
  • 148,279
  • 62
  • 259
  • 315
  • Yes but this is no guarantee that it's internal. I just can write $wrongResponse = Response::getInstance() and it works, no matter where I type it. Furthermore there can be multiple responses, not just one. So Singleton is not very helpful in this case. – Luca Nate Mahler Mar 13 '14 at 11:21
  • Only thing you can do is to use reflections and check what called your method. But this is very heavyweight solution. – hsz Mar 13 '14 at 11:24
  • @LucaNateMahler this pattern is not a singleton because it creates new object every time. – hsz Mar 13 '14 at 11:38
  • Yes you're right. But there is no difference between this and a normal constructor because it's also public. – Luca Nate Mahler Mar 13 '14 at 11:40
  • @hsz That may be the case but it has the exact same problems as a singleton and therefor has no place in OOP – PeeHaa Mar 13 '14 at 11:44
0

Looks like package visibility. But php has none. :^ )

You could use debug_backtrace. For example

namespace One
    {

    class Request
        {

        public function getResponse()
            {
            return new Response();
            }

        }

    class Response
        {

        public function __construct()
            {
            $debug = debug_backtrace();
            if (count($debug) < 2 
                || !isset($debug[1]['class']) 
                || strpos($debug[1]['class'], __NAMESPACE__ . '\\') !== 0)
                {
                die('Invalid context');
                }
            echo 'Created' . PHP_EOL;
            }

        }

    }

namespace Two
    {
    $request = new \One\Request();
    $response = $request->getResponse(); // Should work
    $wrongResponse = new \One\Response(); // Should NOT work
    }

http://3v4l.org/g0dnG#v530

sectus
  • 15,605
  • 5
  • 55
  • 97