SCA Functions
Introducere
Această extensie este EXPERIMENTALĂ. Comportamentul acestei extensii -- inclusiv denumirile funcţiilor sale şi orice alte aspecte documentate în privinţa acestei extensii -- pot să fie modificate fără preaviz într-o versiune viitoare a PHP. Utilizaţi această extensie la propriul risc.
SCA for PHP makes it possible for a PHP programmer to write reusable components, which can be called in a variety of ways, with an identical interface and with a minimum of fuss. At present components can call each other either locally or via Web services, but in the future it is expected that other ways will be possible. It provides the programmer with a way of doing this which will look as natural as possible in PHP.
SCA components use phpDocumentor-style (see https://www.phpdoc.org/) annotations to declare dependencies on other SCA components or Web services. The SCA for PHP runtime resolves these dependencies at runtime on behalf of the components, and thus allows the PHP programmer to focus on the business logic rather than on locating and obtaining references to dependencies.
The SCA for PHP programming model can be extended to support a number of service types, such as REST and Atompub. However, Web services (more accurately, WSDL defined, SOAP/HTTP services), are the only type currently specified.
Components also use annotations to define the interface which they expose as a service. The SCA for PHP runtime will automatically generate WSDL from these annotations, so that an SCA component is easily exposed as a web service. These annotations are a natural extension to those provided by phpDocumentor. Deploying a Web service can be as simple as placing a PHP component under the document root of a web server.
Components also use annotations to specify data structures (expressed using XML schema complex types) which are then handled using Service Data Objects (SDOs).
A PHP script which is not an SCA component and which contains no annotations can use the services of an SCA component. A PHP script or component can make calls to a web service that is not an SCA component, but using the same system of calls or annotations to obtain a reference.
First we show a single SCA component, ConvertedStockQuote which illustrates many of the features of SCA for PHP. It has one method, getQuote(), which given a stock "ticker" obtains a price quote for that stock, converted to a given currency. We shall be using this example as a basis for explaining the SCA for PHP throughout the rest of this document.
Example#1 A sample SCA component
<?php
include "SCA/SCA.php";
/**
* Calculate a stock price for a given ticker symbol in a given currency.
*
* @service
* @binding.soap
*/
class ConvertedStockQuote {
/**
* The currency exchange rate service to use.
*
* @reference
* @binding.php ../ExchangeRate/ExchangeRate.php
*/
public $exchange_rate;
/**
* The stock quote service to use.
*
* @reference
* @binding.soap ../StockQuote/StockQuote.wsdl
*/
public $stock_quote;
/**
* Get a stock quote for a given ticker symbol in a given currency.
*
* @param string $ticker The ticker symbol.
* @param string $currency What currency to convert the value to.
* @return float The stock value is the target currency.
*/
function getQuote($ticker, $currency)
{
$quote = $this->stock_quote->getQuote($ticker);
$rate = $this->exchange_rate->getRate($currency);
return $rate * $quote;
}
}
?>
In this example, we see that an SCA component is implemented by a script containing a PHP class and includes SCA.php. The class contains a mixture of business logic and references to other components or services. In the illustrated getQuote() method there is only business logic, but it relies on the instance variables $stock_quote and $exchange_rate having been initialized. These refer to two other components and will be initialized by the SCA runtime with proxies for these two services, whenever this component executes. The annotations for these two services show one to be a local component, which will be called within the same PHP runtime, and one to be a remote component which will be called via a SOAP request. This component also exposes the getQuote() method both locally and as a web service, so it in turn can be called either locally or remotely.
Necesităţi
If you want to use SCA to consume or produce Web services then you need PHP 5.2.0 or later, built with the soap extension enabled. If you just want to use local components, and do not wish to use the Web service bindings, then this version of SCA for PHP will also run with PHP 5.1.6.
Instalarea
SCA is packaged along with SDO in one combined package on PECL. See https://www.php.net/sdo#sdo.installation for installing the SCA_SDO package from PECL. The SCA code must be on the include path of your PHP installation, for example if it is installed as /usr/local/lib/php/SCA, the include_path directive must include /usr/local/lib/php
Exemple
The examples in the subsequent sections illustrate the following aspects of PHP for SCA:
-
How PHP annotations are used to define PHP classes as SCA components, and how annotations are used to define the services.
-
How an SCA component can be exposed as a Web service
-
How an SCA component can consume a Web service, whether provided by another SCA component or by some other service which knows nothing of SCA
-
How an SCA component can call another SCA component locally (within the same process and on the same call stack)
-
How a client script which is not an SCA component can use the getService call to obtain a proxy for an SCA component.
-
How data structures such as Addresses, or Puchase Orders, are represented as Service Data Objects, and handled.
-
How SCA components are deployed, and in particular how and when WSDL is generated for a service.
-
How parameters are always passed by value (and not by reference) between components, even when the calls are local. This ensures that the semantics of a call do not change depending on the location of a component.
-
How positional parameters to a service are supported, even when the underlying WSDL is document literal wrapped, and naturally supports only named parameters.
-
How business and runtime exceptions are handled.
The structure of a Service Component
A service component is implemented by a class. To identify it as a service component, it contains an @service annotation. The SCA runtime will use the file name of the script to determine the component name, by convention. The class and script file must therefore share the same name.
PHP SCA components always expose a service, and there is no way for a component to be invoked other than to be called as a result of a Web service request, or called directly from another component or from a script. For this reason a valid PHP SCA component will always contain an @service annotation and at least one public method.
Each SCA Component requires that the SCA.php script is included. As well as containing the definition of the SCA class, this script contains executable PHP code that will run whenever the script is called, and which will be responsible for making the component behave as needed.
It is very important that if your file contains other includes, they come before the include for SCA.php. If there are includes after the include for SCA.php, they will not have been processed when the SCA runtime runs your class.
The example below illustrates this overall structure
Example#2 The structure of an SCA for PHP component
<?php
// any includes
include "SCA/SCA.php";
/**
* @service
*/
class ConvertedStockQuote {
// instance variables, business logic, including at least one public method
}
?>
Obtaining a proxy for another Service Component
One SCA component can call the service provided by another SCA component. The service a component provides is made up of all of its public methods. SCA for PHP currently provides two ways for one component to call another: either locally (i.e. within the same PHP run-time, and on the same call stack) or remotely if the called component exposes a Web service binding.
In order for one component to call another, the calling component needs a proxy for the called component. This proxy is usually provided as an instance variable in the calling component, though proxies can also be obtained with the SCA::getService() call, as we shall see later. When a component is constructed, proxies are constructed for any instance variable which refer to another component, and these proxies are "injected" into the instance variables. Proxies are always used, whether the component is local or remote, in order to provide identical calling behavior between remote and local calls (for example, local calls are made to always pass data by-value). The proxies know how to locate the required component and to pass the calls made on to them.
Instance variables which are intended to hold proxies for services are indicated by the two PHPDocumentor-style annotations, @reference and @binding. Both annotations are placed in the documentation section for a class instance variable, as shown by the code below.
The @reference annotation before an instance variable indicates that that instance variable is to be initialized with a proxy to a component.
The @binding annotation has two forms @binding.php and @binding.soap, and indicates that the proxy is either for a local component or for a Web service respectively. For both @binding.php and @binding.soap, the annotation gives a target URI.
At the moment, with the annotation-based method of specifying dependencies, the only way to alter the intended target of a reference is to alter the annotation within the component.
In our ConvertedStockQuote example, the $exchange_rate instance variable will be initialized with a proxy to the local ExchangeRate component whenever an instance of the ConvertedStockQuote is constructed.
Example#3 Obtaining a proxy for a local PHP class
<?php
/**
* The currency exchange rate service to use.
*
* @reference
* @binding.php ../ExchangeRate/ExchangeRate.php
*/
public $exchange_rate;
?>
For @binding.php, the URI identifies the location of the script containing the implementation of the component. The component will be called locally. The service provided is the set of public methods of the component. The URI must be a simple pathname, either absolute or relative. The component will be loaded with the PHP include directive, after testing to see if it is already loaded with class_exists(). If the URI is a relative path, it is resolved relative to the component containing the annotation. Note that this is different from the normal PHP behaviour where scripts would be looked for along the PHP include_path, This is intended to provide some location-independence for cross-component references.
If this ExchangeRate service were remote and to be called as a Web service, only the @binding line changes. Instead of giving the location of a PHP class, it gives the location of the WSDL describing the web service. In our example component, this is illustrated by the second reference:
Example#4 Obtaining a proxy for a web service
<?php
/**
* The stock quote service to use.
*
* @reference
* @binding.soap ../StockQuote/StockQuote.wsdl
*/
public $stock_quote;
?>
The StockQuote component will be called via a Web service request. In this case the URI for the WSDL can be a simple pathname, or may contain a PHP wrapper and begin, for example, with file:// or https://. In the event that it is a simple pathname, it can be absolute or relative, and if relative will be resolved relative to the component containing the annotation. Note that this is like the behaviour for @binding.php, and different from the normal PHP behaviour where the file would be looked for relative to the PHP current working directory, which would usually be the location of the first script to be called. This behaviour is intended to give consistency across the different bindings and to provide some location-independence for references between components.
Calling another Service Component
The ConvertedStockQuote example also calls the proxies for the two components to which it refers.
Example#5 Calling services
<?php
$quote = $this->stock_quote->getQuote(