blob: e4b4a17c0c4c7cf7a70afeb427aab63ed56678a1 [file] [log] [blame]
Roger Meier21c0a852012-09-05 19:47:14 +00001<?php
2/*
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 * ClassLoader to load Thrift library and definitions
Roger Thomas6fb59232014-11-04 10:09:23 +000021 * Inspired from UniversalClassLoader from Symfony 2
Roger Meier21c0a852012-09-05 19:47:14 +000022 *
23 * @package thrift.classloader
24 */
25
26namespace Thrift\ClassLoader;
27
28class ThriftClassLoader
29{
30 /**
31 * Namespaces path
32 * @var array
33 */
34 protected $namespaces = array();
35
36 /**
37 * Thrift definition paths
38 * @var type
39 */
40 protected $definitions = array();
41
42 /**
panivkodfe7f302020-03-04 15:05:17 +020043 * Do we use APCu cache ?
Roger Meier21c0a852012-09-05 19:47:14 +000044 * @var boolean
45 */
panivkodfe7f302020-03-04 15:05:17 +020046 protected $apcu = false;
Roger Meier21c0a852012-09-05 19:47:14 +000047
48 /**
panivkodfe7f302020-03-04 15:05:17 +020049 * APCu Cache prefix
Roger Meier21c0a852012-09-05 19:47:14 +000050 * @var string
51 */
panivkodfe7f302020-03-04 15:05:17 +020052 protected $apcu_prefix;
Roger Meier21c0a852012-09-05 19:47:14 +000053
54 /**
panivkodfe7f302020-03-04 15:05:17 +020055 * Set autoloader to use APCu cache
Roger Meier21c0a852012-09-05 19:47:14 +000056 * @param boolean $apc
panivkodfe7f302020-03-04 15:05:17 +020057 * @param string $apcu_prefix
Roger Meier21c0a852012-09-05 19:47:14 +000058 */
panivkodfe7f302020-03-04 15:05:17 +020059 public function __construct($apc = false, $apcu_prefix = null)
Roger Meier21c0a852012-09-05 19:47:14 +000060 {
panivkodfe7f302020-03-04 15:05:17 +020061 $this->apcu = $apc;
62 $this->apcu_prefix = $apcu_prefix;
Roger Meier21c0a852012-09-05 19:47:14 +000063 }
64
65 /**
66 * Registers a namespace.
67 *
Robert Lub03ca012018-01-18 19:06:39 +080068 * @param string $namespace The namespace
69 * @param array|string $paths The location(s) of the namespace
Roger Meier21c0a852012-09-05 19:47:14 +000070 */
71 public function registerNamespace($namespace, $paths)
72 {
Robert Lub03ca012018-01-18 19:06:39 +080073 $this->namespaces[$namespace] = (array)$paths;
Roger Meier21c0a852012-09-05 19:47:14 +000074 }
75
76 /**
77 * Registers a Thrift definition namespace.
78 *
Robert Lub03ca012018-01-18 19:06:39 +080079 * @param string $namespace The definition namespace
80 * @param array|string $paths The location(s) of the definition namespace
Roger Meier21c0a852012-09-05 19:47:14 +000081 */
82 public function registerDefinition($namespace, $paths)
83 {
Robert Lub03ca012018-01-18 19:06:39 +080084 $this->definitions[$namespace] = (array)$paths;
Roger Meier21c0a852012-09-05 19:47:14 +000085 }
86
87 /**
88 * Registers this instance as an autoloader.
89 *
90 * @param Boolean $prepend Whether to prepend the autoloader or not
91 */
92 public function register($prepend = false)
93 {
94 spl_autoload_register(array($this, 'loadClass'), true, $prepend);
95 }
96
97 /**
98 * Loads the given class, definition or interface.
99 *
100 * @param string $class The name of the class
101 */
102 public function loadClass($class)
103 {
panivkodfe7f302020-03-04 15:05:17 +0200104 if ((true === $this->apcu && ($file = $this->findFileInApcu($class))) or
Roger Meier21c0a852012-09-05 19:47:14 +0000105 ($file = $this->findFile($class))
Robert Lub03ca012018-01-18 19:06:39 +0800106 ) {
Roger Meier21c0a852012-09-05 19:47:14 +0000107 require_once $file;
108 }
109 }
110
111 /**
panivkodfe7f302020-03-04 15:05:17 +0200112 * Loads the given class or interface in APCu.
Roger Thomas6fb59232014-11-04 10:09:23 +0000113 * @param string $class The name of the class
Roger Meier21c0a852012-09-05 19:47:14 +0000114 * @return string
115 */
panivkodfe7f302020-03-04 15:05:17 +0200116 protected function findFileInApcu($class)
Roger Meier21c0a852012-09-05 19:47:14 +0000117 {
panivkodfe7f302020-03-04 15:05:17 +0200118 if (false === $file = apcu_fetch($this->apcu_prefix . $class)) {
119 apcu_store($this->apcu_prefix . $class, $file = $this->findFile($class));
Roger Meier21c0a852012-09-05 19:47:14 +0000120 }
121
122 return $file;
123 }
124
125 /**
126 * Find class in namespaces or definitions directories
Roger Thomas6fb59232014-11-04 10:09:23 +0000127 * @param string $class
Roger Meier21c0a852012-09-05 19:47:14 +0000128 * @return string
129 */
130 public function findFile($class)
131 {
132 // Remove first backslash
Roger Thomas6fb59232014-11-04 10:09:23 +0000133 if ('\\' == $class[0]) {
Roger Meier21c0a852012-09-05 19:47:14 +0000134 $class = substr($class, 1);
135 }
136
Roger Thomas6fb59232014-11-04 10:09:23 +0000137 if (false !== $pos = strrpos($class, '\\')) {
Roger Meier21c0a852012-09-05 19:47:14 +0000138 // Namespaced class name
139 $namespace = substr($class, 0, $pos);
140
141 // Iterate in normal namespaces
Roger Thomas6fb59232014-11-04 10:09:23 +0000142 foreach ($this->namespaces as $ns => $dirs) {
Roger Meier21c0a852012-09-05 19:47:14 +0000143 //Don't interfere with other autoloaders
Roger Thomas6fb59232014-11-04 10:09:23 +0000144 if (0 !== strpos($namespace, $ns)) {
Roger Meier21c0a852012-09-05 19:47:14 +0000145 continue;
146 }
147
Roger Thomas6fb59232014-11-04 10:09:23 +0000148 foreach ($dirs as $dir) {
Roger Meier21c0a852012-09-05 19:47:14 +0000149 $className = substr($class, $pos + 1);
150
Robert Lub03ca012018-01-18 19:06:39 +0800151 $file = $dir . DIRECTORY_SEPARATOR .
152 str_replace('\\', DIRECTORY_SEPARATOR, $namespace) .
153 DIRECTORY_SEPARATOR .
154 $className . '.php';
Roger Meier21c0a852012-09-05 19:47:14 +0000155
Roger Thomas6fb59232014-11-04 10:09:23 +0000156 if (file_exists($file)) {
Roger Meier21c0a852012-09-05 19:47:14 +0000157 return $file;
158 }
159 }
160 }
161
162 // Iterate in Thrift namespaces
163
164 // Remove first part of namespace
165 $m = explode('\\', $class);
166
167 // Ignore wrong call
Roger Thomas6fb59232014-11-04 10:09:23 +0000168 if (count($m) <= 1) {
Roger Meier21c0a852012-09-05 19:47:14 +0000169 return;
170 }
171
172 $class = array_pop($m);
173 $namespace = implode('\\', $m);
174
Roger Thomas6fb59232014-11-04 10:09:23 +0000175 foreach ($this->definitions as $ns => $dirs) {
Roger Meier21c0a852012-09-05 19:47:14 +0000176 //Don't interfere with other autoloaders
Roger Thomas6fb59232014-11-04 10:09:23 +0000177 if (0 !== strpos($namespace, $ns)) {
Roger Meier21c0a852012-09-05 19:47:14 +0000178 continue;
179 }
180
Roger Thomas6fb59232014-11-04 10:09:23 +0000181 foreach ($dirs as $dir) {
Roger Meier21c0a852012-09-05 19:47:14 +0000182 /**
183 * Available in service: Interface, Client, Processor, Rest
184 * And every service methods (_.+)
185 */
Robert Lub03ca012018-01-18 19:06:39 +0800186 if (0 === preg_match('#(.+)(if|client|processor|rest)$#i', $class, $n) and
Roger Meier21c0a852012-09-05 19:47:14 +0000187 0 === preg_match('#(.+)_[a-z0-9]+_(args|result)$#i', $class, $n)
Robert Lub03ca012018-01-18 19:06:39 +0800188 ) {
Roger Meier21c0a852012-09-05 19:47:14 +0000189 $className = 'Types';
Roger Thomas6fb59232014-11-04 10:09:23 +0000190 } else {
Roger Meier21c0a852012-09-05 19:47:14 +0000191 $className = $n[1];
192 }
193
Robert Lub03ca012018-01-18 19:06:39 +0800194 $file = $dir . DIRECTORY_SEPARATOR .
195 str_replace('\\', DIRECTORY_SEPARATOR, $namespace) .
196 DIRECTORY_SEPARATOR .
197 $className . '.php';
Roger Meier21c0a852012-09-05 19:47:14 +0000198
Roger Thomas6fb59232014-11-04 10:09:23 +0000199 if (file_exists($file)) {
Roger Meier21c0a852012-09-05 19:47:14 +0000200 return $file;
201 }
202 }
203 }
204 }
205 }
206}